1ea7f1c8cSNeel Natu /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4ea7f1c8cSNeel Natu * Copyright (c) 2012 NetApp, Inc. 5ea7f1c8cSNeel Natu * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6ea7f1c8cSNeel Natu * All rights reserved. 7ea7f1c8cSNeel Natu * 8ea7f1c8cSNeel Natu * Redistribution and use in source and binary forms, with or without 9ea7f1c8cSNeel Natu * modification, are permitted provided that the following conditions 10ea7f1c8cSNeel Natu * are met: 11ea7f1c8cSNeel Natu * 1. Redistributions of source code must retain the above copyright 12ea7f1c8cSNeel Natu * notice, this list of conditions and the following disclaimer. 13ea7f1c8cSNeel Natu * 2. Redistributions in binary form must reproduce the above copyright 14ea7f1c8cSNeel Natu * notice, this list of conditions and the following disclaimer in the 15ea7f1c8cSNeel Natu * documentation and/or other materials provided with the distribution. 16ea7f1c8cSNeel Natu * 17ea7f1c8cSNeel Natu * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18ea7f1c8cSNeel Natu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19ea7f1c8cSNeel Natu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20ea7f1c8cSNeel Natu * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21ea7f1c8cSNeel Natu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22ea7f1c8cSNeel Natu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23ea7f1c8cSNeel Natu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24ea7f1c8cSNeel Natu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25ea7f1c8cSNeel Natu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26ea7f1c8cSNeel Natu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27ea7f1c8cSNeel Natu * SUCH DAMAGE. 28ea7f1c8cSNeel Natu */ 29ea7f1c8cSNeel Natu 30ea7f1c8cSNeel Natu #include <sys/types.h> 31ea7f1c8cSNeel Natu #include <dev/ic/ns16550.h> 32ea7f1c8cSNeel Natu 33483d953aSJohn Baldwin #include <machine/vmm_snapshot.h> 34483d953aSJohn Baldwin 35d1c5d0cfSMark Johnston #include <assert.h> 36ea7f1c8cSNeel Natu #include <stdio.h> 37ea7f1c8cSNeel Natu #include <stdlib.h> 3800ef17beSBartek Rutkowski #include <errno.h> 39ea7f1c8cSNeel Natu #include <unistd.h> 40ea7f1c8cSNeel Natu #include <stdbool.h> 41ea7f1c8cSNeel Natu #include <string.h> 42ea7f1c8cSNeel Natu #include <pthread.h> 43ea7f1c8cSNeel Natu 44d1c5d0cfSMark Johnston #include "uart_backend.h" 45ea7f1c8cSNeel Natu #include "uart_emul.h" 46ea7f1c8cSNeel Natu 47ea7f1c8cSNeel Natu #define COM1_BASE 0x3F8 48ea7f1c8cSNeel Natu #define COM1_IRQ 4 49ea7f1c8cSNeel Natu #define COM2_BASE 0x2F8 50ea7f1c8cSNeel Natu #define COM2_IRQ 3 51eed1cc6cSPeter Grehan #define COM3_BASE 0x3E8 52eed1cc6cSPeter Grehan #define COM3_IRQ 4 53eed1cc6cSPeter Grehan #define COM4_BASE 0x2E8 54eed1cc6cSPeter Grehan #define COM4_IRQ 3 55ea7f1c8cSNeel Natu 56ea7f1c8cSNeel Natu #define DEFAULT_RCLK 1843200 57d1eb515fSEd Maste #define DEFAULT_BAUD 115200 58ea7f1c8cSNeel Natu 59ea7f1c8cSNeel Natu #define FCR_RX_MASK 0xC0 60ea7f1c8cSNeel Natu 61ea7f1c8cSNeel Natu #define MCR_OUT1 0x04 62ea7f1c8cSNeel Natu #define MCR_OUT2 0x08 63ea7f1c8cSNeel Natu 64ea7f1c8cSNeel Natu #define MSR_DELTA_MASK 0x0f 65ea7f1c8cSNeel Natu 66ea7f1c8cSNeel Natu #ifndef REG_SCR 67ea7f1c8cSNeel Natu #define REG_SCR com_scr 68ea7f1c8cSNeel Natu #endif 69ea7f1c8cSNeel Natu 70ea7f1c8cSNeel Natu static struct { 71ea7f1c8cSNeel Natu int baseaddr; 72ea7f1c8cSNeel Natu int irq; 73ea7f1c8cSNeel Natu bool inuse; 74ea7f1c8cSNeel Natu } uart_lres[] = { 75ea7f1c8cSNeel Natu { COM1_BASE, COM1_IRQ, false}, 76ea7f1c8cSNeel Natu { COM2_BASE, COM2_IRQ, false}, 77eed1cc6cSPeter Grehan { COM3_BASE, COM3_IRQ, false}, 78eed1cc6cSPeter Grehan { COM4_BASE, COM4_IRQ, false}, 79ea7f1c8cSNeel Natu }; 80ea7f1c8cSNeel Natu 81ea7f1c8cSNeel Natu #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 82ea7f1c8cSNeel Natu 83d1c5d0cfSMark Johnston struct uart_ns16550_softc { 84d1c5d0cfSMark Johnston struct uart_softc *backend; 85ea7f1c8cSNeel Natu 86ea7f1c8cSNeel Natu uint8_t data; /* Data register (R/W) */ 87ea7f1c8cSNeel Natu uint8_t ier; /* Interrupt enable register (R/W) */ 88ea7f1c8cSNeel Natu uint8_t lcr; /* Line control register (R/W) */ 89ea7f1c8cSNeel Natu uint8_t mcr; /* Modem control register (R/W) */ 90ea7f1c8cSNeel Natu uint8_t lsr; /* Line status register (R/W) */ 91ea7f1c8cSNeel Natu uint8_t msr; /* Modem status register (R/W) */ 92ea7f1c8cSNeel Natu uint8_t fcr; /* FIFO control register (W) */ 93ea7f1c8cSNeel Natu uint8_t scr; /* Scratch register (R/W) */ 94ea7f1c8cSNeel Natu 95ea7f1c8cSNeel Natu uint8_t dll; /* Baudrate divisor latch LSB */ 96ea7f1c8cSNeel Natu uint8_t dlh; /* Baudrate divisor latch MSB */ 97ea7f1c8cSNeel Natu 98ea7f1c8cSNeel Natu bool thre_int_pending; /* THRE interrupt pending */ 99ea7f1c8cSNeel Natu 100ea7f1c8cSNeel Natu void *arg; 101ea7f1c8cSNeel Natu uart_intr_func_t intr_assert; 102ea7f1c8cSNeel Natu uart_intr_func_t intr_deassert; 103ea7f1c8cSNeel Natu }; 104ea7f1c8cSNeel Natu 105ccfe4c3fSNeel Natu static uint8_t 106ccfe4c3fSNeel Natu modem_status(uint8_t mcr) 107ccfe4c3fSNeel Natu { 108ccfe4c3fSNeel Natu uint8_t msr; 109ccfe4c3fSNeel Natu 110ccfe4c3fSNeel Natu if (mcr & MCR_LOOPBACK) { 111ccfe4c3fSNeel Natu /* 112ccfe4c3fSNeel Natu * In the loopback mode certain bits from the MCR are 113ccfe4c3fSNeel Natu * reflected back into MSR. 114ccfe4c3fSNeel Natu */ 115ccfe4c3fSNeel Natu msr = 0; 116ccfe4c3fSNeel Natu if (mcr & MCR_RTS) 117ccfe4c3fSNeel Natu msr |= MSR_CTS; 118ccfe4c3fSNeel Natu if (mcr & MCR_DTR) 119ccfe4c3fSNeel Natu msr |= MSR_DSR; 120ccfe4c3fSNeel Natu if (mcr & MCR_OUT1) 121ccfe4c3fSNeel Natu msr |= MSR_RI; 122ccfe4c3fSNeel Natu if (mcr & MCR_OUT2) 123ccfe4c3fSNeel Natu msr |= MSR_DCD; 124ccfe4c3fSNeel Natu } else { 125ccfe4c3fSNeel Natu /* 126ccfe4c3fSNeel Natu * Always assert DCD and DSR so tty open doesn't block 127ccfe4c3fSNeel Natu * even if CLOCAL is turned off. 128ccfe4c3fSNeel Natu */ 129ccfe4c3fSNeel Natu msr = MSR_DCD | MSR_DSR; 130ccfe4c3fSNeel Natu } 131ccfe4c3fSNeel Natu assert((msr & MSR_DELTA_MASK) == 0); 132ccfe4c3fSNeel Natu 133ccfe4c3fSNeel Natu return (msr); 134ccfe4c3fSNeel Natu } 135ccfe4c3fSNeel Natu 136ea7f1c8cSNeel Natu /* 137ea7f1c8cSNeel Natu * The IIR returns a prioritized interrupt reason: 138ea7f1c8cSNeel Natu * - receive data available 139ea7f1c8cSNeel Natu * - transmit holding register empty 140ea7f1c8cSNeel Natu * - modem status change 141ea7f1c8cSNeel Natu * 142ea7f1c8cSNeel Natu * Return an interrupt reason if one is available. 143ea7f1c8cSNeel Natu */ 144ea7f1c8cSNeel Natu static int 145d1c5d0cfSMark Johnston uart_intr_reason(struct uart_ns16550_softc *sc) 146ea7f1c8cSNeel Natu { 147ea7f1c8cSNeel Natu 148ea7f1c8cSNeel Natu if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 149ea7f1c8cSNeel Natu return (IIR_RLS); 150d1c5d0cfSMark Johnston else if (uart_rxfifo_numchars(sc->backend) > 0 && 151d1c5d0cfSMark Johnston (sc->ier & IER_ERXRDY) != 0) 152ea7f1c8cSNeel Natu return (IIR_RXTOUT); 153ea7f1c8cSNeel Natu else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 154ea7f1c8cSNeel Natu return (IIR_TXRDY); 155ea7f1c8cSNeel Natu else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 156ea7f1c8cSNeel Natu return (IIR_MLSC); 157ea7f1c8cSNeel Natu else 158ea7f1c8cSNeel Natu return (IIR_NOPEND); 159ea7f1c8cSNeel Natu } 160ea7f1c8cSNeel Natu 161ea7f1c8cSNeel Natu static void 162d1c5d0cfSMark Johnston uart_reset(struct uart_ns16550_softc *sc) 163ea7f1c8cSNeel Natu { 164ea7f1c8cSNeel Natu uint16_t divisor; 165ea7f1c8cSNeel Natu 166ea7f1c8cSNeel Natu divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 167ea7f1c8cSNeel Natu sc->dll = divisor; 168ea7f1c8cSNeel Natu sc->dlh = divisor >> 16; 169ccfe4c3fSNeel Natu sc->msr = modem_status(sc->mcr); 170ea7f1c8cSNeel Natu 171d1c5d0cfSMark Johnston uart_rxfifo_reset(sc->backend, 1); 172ea7f1c8cSNeel Natu } 173ea7f1c8cSNeel Natu 174ea7f1c8cSNeel Natu /* 175ea7f1c8cSNeel Natu * Toggle the COM port's intr pin depending on whether or not we have an 176ea7f1c8cSNeel Natu * interrupt condition to report to the processor. 177ea7f1c8cSNeel Natu */ 178ea7f1c8cSNeel Natu static void 179d1c5d0cfSMark Johnston uart_toggle_intr(struct uart_ns16550_softc *sc) 180ea7f1c8cSNeel Natu { 181ea7f1c8cSNeel Natu uint8_t intr_reason; 182ea7f1c8cSNeel Natu 183ea7f1c8cSNeel Natu intr_reason = uart_intr_reason(sc); 184ea7f1c8cSNeel Natu 185ea7f1c8cSNeel Natu if (intr_reason == IIR_NOPEND) 186ea7f1c8cSNeel Natu (*sc->intr_deassert)(sc->arg); 187ea7f1c8cSNeel Natu else 188ea7f1c8cSNeel Natu (*sc->intr_assert)(sc->arg); 189ea7f1c8cSNeel Natu } 190ea7f1c8cSNeel Natu 191ea7f1c8cSNeel Natu static void 192d1c5d0cfSMark Johnston uart_drain(int fd __unused, enum ev_type ev, void *arg) 193ea7f1c8cSNeel Natu { 194d1c5d0cfSMark Johnston struct uart_ns16550_softc *sc; 195d1c5d0cfSMark Johnston bool loopback; 196ea7f1c8cSNeel Natu 197ea7f1c8cSNeel Natu sc = arg; 198ea7f1c8cSNeel Natu 199ea7f1c8cSNeel Natu assert(ev == EVF_READ); 200ea7f1c8cSNeel Natu 201ea7f1c8cSNeel Natu /* 202ea7f1c8cSNeel Natu * This routine is called in the context of the mevent thread 203ea7f1c8cSNeel Natu * to take out the softc lock to protect against concurrent 204ea7f1c8cSNeel Natu * access from a vCPU i/o exit 205ea7f1c8cSNeel Natu */ 206*e10b9d66SSHENG-YI HONG uart_softc_lock(sc->backend); 207ea7f1c8cSNeel Natu 208d1c5d0cfSMark Johnston loopback = (sc->mcr & MCR_LOOPBACK) != 0; 209d1c5d0cfSMark Johnston uart_rxfifo_drain(sc->backend, loopback); 210d1c5d0cfSMark Johnston if (!loopback) 211ea7f1c8cSNeel Natu uart_toggle_intr(sc); 212ea7f1c8cSNeel Natu 213*e10b9d66SSHENG-YI HONG uart_softc_unlock(sc->backend); 214ea7f1c8cSNeel Natu } 215ea7f1c8cSNeel Natu 216ea7f1c8cSNeel Natu void 217d1c5d0cfSMark Johnston uart_ns16550_write(struct uart_ns16550_softc *sc, int offset, uint8_t value) 218ea7f1c8cSNeel Natu { 219ea7f1c8cSNeel Natu int fifosz; 220ea7f1c8cSNeel Natu uint8_t msr; 221ea7f1c8cSNeel Natu 222*e10b9d66SSHENG-YI HONG uart_softc_lock(sc->backend); 223ea7f1c8cSNeel Natu 224ea7f1c8cSNeel Natu /* 225ea7f1c8cSNeel Natu * Take care of the special case DLAB accesses first 226ea7f1c8cSNeel Natu */ 227ea7f1c8cSNeel Natu if ((sc->lcr & LCR_DLAB) != 0) { 228ea7f1c8cSNeel Natu if (offset == REG_DLL) { 229ea7f1c8cSNeel Natu sc->dll = value; 230ea7f1c8cSNeel Natu goto done; 231ea7f1c8cSNeel Natu } 232ea7f1c8cSNeel Natu 233ea7f1c8cSNeel Natu if (offset == REG_DLH) { 234ea7f1c8cSNeel Natu sc->dlh = value; 235ea7f1c8cSNeel Natu goto done; 236ea7f1c8cSNeel Natu } 237ea7f1c8cSNeel Natu } 238ea7f1c8cSNeel Natu 239ea7f1c8cSNeel Natu switch (offset) { 240ea7f1c8cSNeel Natu case REG_DATA: 241d1c5d0cfSMark Johnston if (uart_rxfifo_putchar(sc->backend, value, 242d1c5d0cfSMark Johnston (sc->mcr & MCR_LOOPBACK) != 0)) 243ea7f1c8cSNeel Natu sc->lsr |= LSR_OE; 244ea7f1c8cSNeel Natu sc->thre_int_pending = true; 245ea7f1c8cSNeel Natu break; 246ea7f1c8cSNeel Natu case REG_IER: 24755792380SConrad Meyer /* Set pending when IER_ETXRDY is raised (edge-triggered). */ 24855792380SConrad Meyer if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0) 24955792380SConrad Meyer sc->thre_int_pending = true; 250ea7f1c8cSNeel Natu /* 251ea7f1c8cSNeel Natu * Apply mask so that bits 4-7 are 0 252ea7f1c8cSNeel Natu * Also enables bits 0-3 only if they're 1 253ea7f1c8cSNeel Natu */ 254ea7f1c8cSNeel Natu sc->ier = value & 0x0F; 255ea7f1c8cSNeel Natu break; 256ea7f1c8cSNeel Natu case REG_FCR: 257ea7f1c8cSNeel Natu /* 258ea7f1c8cSNeel Natu * When moving from FIFO and 16450 mode and vice versa, 259ea7f1c8cSNeel Natu * the FIFO contents are reset. 260ea7f1c8cSNeel Natu */ 261ea7f1c8cSNeel Natu if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 262d1c5d0cfSMark Johnston fifosz = (value & FCR_ENABLE) ? 263d1c5d0cfSMark Johnston uart_rxfifo_size(sc->backend) : 1; 264d1c5d0cfSMark Johnston uart_rxfifo_reset(sc->backend, fifosz); 265ea7f1c8cSNeel Natu } 266ea7f1c8cSNeel Natu 267ea7f1c8cSNeel Natu /* 268ea7f1c8cSNeel Natu * The FCR_ENABLE bit must be '1' for the programming 269ea7f1c8cSNeel Natu * of other FCR bits to be effective. 270ea7f1c8cSNeel Natu */ 271ea7f1c8cSNeel Natu if ((value & FCR_ENABLE) == 0) { 272ea7f1c8cSNeel Natu sc->fcr = 0; 273ea7f1c8cSNeel Natu } else { 274ea7f1c8cSNeel Natu if ((value & FCR_RCV_RST) != 0) 275d1c5d0cfSMark Johnston uart_rxfifo_reset(sc->backend, 276d1c5d0cfSMark Johnston uart_rxfifo_size(sc->backend)); 277ea7f1c8cSNeel Natu 278ea7f1c8cSNeel Natu sc->fcr = value & 279ea7f1c8cSNeel Natu (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 280ea7f1c8cSNeel Natu } 281ea7f1c8cSNeel Natu break; 282ea7f1c8cSNeel Natu case REG_LCR: 283ea7f1c8cSNeel Natu sc->lcr = value; 284ea7f1c8cSNeel Natu break; 285ea7f1c8cSNeel Natu case REG_MCR: 286ea7f1c8cSNeel Natu /* Apply mask so that bits 5-7 are 0 */ 287ea7f1c8cSNeel Natu sc->mcr = value & 0x1F; 288ccfe4c3fSNeel Natu msr = modem_status(sc->mcr); 289ea7f1c8cSNeel Natu 290ea7f1c8cSNeel Natu /* 291ea7f1c8cSNeel Natu * Detect if there has been any change between the 292ea7f1c8cSNeel Natu * previous and the new value of MSR. If there is 293ea7f1c8cSNeel Natu * then assert the appropriate MSR delta bit. 294ea7f1c8cSNeel Natu */ 295ea7f1c8cSNeel Natu if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 296ea7f1c8cSNeel Natu sc->msr |= MSR_DCTS; 297ea7f1c8cSNeel Natu if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 298ea7f1c8cSNeel Natu sc->msr |= MSR_DDSR; 299ea7f1c8cSNeel Natu if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 300ea7f1c8cSNeel Natu sc->msr |= MSR_DDCD; 301ea7f1c8cSNeel Natu if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 302ea7f1c8cSNeel Natu sc->msr |= MSR_TERI; 303ea7f1c8cSNeel Natu 304ea7f1c8cSNeel Natu /* 305ea7f1c8cSNeel Natu * Update the value of MSR while retaining the delta 306ea7f1c8cSNeel Natu * bits. 307ea7f1c8cSNeel Natu */ 308ea7f1c8cSNeel Natu sc->msr &= MSR_DELTA_MASK; 309ea7f1c8cSNeel Natu sc->msr |= msr; 310ea7f1c8cSNeel Natu break; 311ea7f1c8cSNeel Natu case REG_LSR: 312ea7f1c8cSNeel Natu /* 313ea7f1c8cSNeel Natu * Line status register is not meant to be written to 314ea7f1c8cSNeel Natu * during normal operation. 315ea7f1c8cSNeel Natu */ 316ea7f1c8cSNeel Natu break; 317ea7f1c8cSNeel Natu case REG_MSR: 318ea7f1c8cSNeel Natu /* 319ea7f1c8cSNeel Natu * As far as I can tell MSR is a read-only register. 320ea7f1c8cSNeel Natu */ 321ea7f1c8cSNeel Natu break; 322ea7f1c8cSNeel Natu case REG_SCR: 323ea7f1c8cSNeel Natu sc->scr = value; 324ea7f1c8cSNeel Natu break; 325ea7f1c8cSNeel Natu default: 326ea7f1c8cSNeel Natu break; 327ea7f1c8cSNeel Natu } 328ea7f1c8cSNeel Natu 329ea7f1c8cSNeel Natu done: 330ea7f1c8cSNeel Natu uart_toggle_intr(sc); 331*e10b9d66SSHENG-YI HONG uart_softc_unlock(sc->backend); 332ea7f1c8cSNeel Natu } 333ea7f1c8cSNeel Natu 334ea7f1c8cSNeel Natu uint8_t 335d1c5d0cfSMark Johnston uart_ns16550_read(struct uart_ns16550_softc *sc, int offset) 336ea7f1c8cSNeel Natu { 337ea7f1c8cSNeel Natu uint8_t iir, intr_reason, reg; 338ea7f1c8cSNeel Natu 339*e10b9d66SSHENG-YI HONG uart_softc_lock(sc->backend); 340ea7f1c8cSNeel Natu 341ea7f1c8cSNeel Natu /* 342ea7f1c8cSNeel Natu * Take care of the special case DLAB accesses first 343ea7f1c8cSNeel Natu */ 344ea7f1c8cSNeel Natu if ((sc->lcr & LCR_DLAB) != 0) { 345ea7f1c8cSNeel Natu if (offset == REG_DLL) { 346ea7f1c8cSNeel Natu reg = sc->dll; 347ea7f1c8cSNeel Natu goto done; 348ea7f1c8cSNeel Natu } 349ea7f1c8cSNeel Natu 350ea7f1c8cSNeel Natu if (offset == REG_DLH) { 351ea7f1c8cSNeel Natu reg = sc->dlh; 352ea7f1c8cSNeel Natu goto done; 353ea7f1c8cSNeel Natu } 354ea7f1c8cSNeel Natu } 355ea7f1c8cSNeel Natu 356ea7f1c8cSNeel Natu switch (offset) { 357ea7f1c8cSNeel Natu case REG_DATA: 358d1c5d0cfSMark Johnston reg = uart_rxfifo_getchar(sc->backend); 359ea7f1c8cSNeel Natu break; 360ea7f1c8cSNeel Natu case REG_IER: 361ea7f1c8cSNeel Natu reg = sc->ier; 362ea7f1c8cSNeel Natu break; 363ea7f1c8cSNeel Natu case REG_IIR: 364ea7f1c8cSNeel Natu iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 365ea7f1c8cSNeel Natu 366ea7f1c8cSNeel Natu intr_reason = uart_intr_reason(sc); 367ea7f1c8cSNeel Natu 368ea7f1c8cSNeel Natu /* 369ea7f1c8cSNeel Natu * Deal with side effects of reading the IIR register 370ea7f1c8cSNeel Natu */ 371ea7f1c8cSNeel Natu if (intr_reason == IIR_TXRDY) 372ea7f1c8cSNeel Natu sc->thre_int_pending = false; 373ea7f1c8cSNeel Natu 374ea7f1c8cSNeel Natu iir |= intr_reason; 375ea7f1c8cSNeel Natu 376ea7f1c8cSNeel Natu reg = iir; 377ea7f1c8cSNeel Natu break; 378ea7f1c8cSNeel Natu case REG_LCR: 379ea7f1c8cSNeel Natu reg = sc->lcr; 380ea7f1c8cSNeel Natu break; 381ea7f1c8cSNeel Natu case REG_MCR: 382ea7f1c8cSNeel Natu reg = sc->mcr; 383ea7f1c8cSNeel Natu break; 384ea7f1c8cSNeel Natu case REG_LSR: 385ea7f1c8cSNeel Natu /* Transmitter is always ready for more data */ 386ea7f1c8cSNeel Natu sc->lsr |= LSR_TEMT | LSR_THRE; 387ea7f1c8cSNeel Natu 388ea7f1c8cSNeel Natu /* Check for new receive data */ 389d1c5d0cfSMark Johnston if (uart_rxfifo_numchars(sc->backend) > 0) 390ea7f1c8cSNeel Natu sc->lsr |= LSR_RXRDY; 391ea7f1c8cSNeel Natu else 392ea7f1c8cSNeel Natu sc->lsr &= ~LSR_RXRDY; 393ea7f1c8cSNeel Natu 394ea7f1c8cSNeel Natu reg = sc->lsr; 395ea7f1c8cSNeel Natu 396ea7f1c8cSNeel Natu /* The LSR_OE bit is cleared on LSR read */ 397ea7f1c8cSNeel Natu sc->lsr &= ~LSR_OE; 398ea7f1c8cSNeel Natu break; 399ea7f1c8cSNeel Natu case REG_MSR: 400ea7f1c8cSNeel Natu /* 401ea7f1c8cSNeel Natu * MSR delta bits are cleared on read 402ea7f1c8cSNeel Natu */ 403ea7f1c8cSNeel Natu reg = sc->msr; 404ea7f1c8cSNeel Natu sc->msr &= ~MSR_DELTA_MASK; 405ea7f1c8cSNeel Natu break; 406ea7f1c8cSNeel Natu case REG_SCR: 407ea7f1c8cSNeel Natu reg = sc->scr; 408ea7f1c8cSNeel Natu break; 409ea7f1c8cSNeel Natu default: 410ea7f1c8cSNeel Natu reg = 0xFF; 411ea7f1c8cSNeel Natu break; 412ea7f1c8cSNeel Natu } 413ea7f1c8cSNeel Natu 414ea7f1c8cSNeel Natu done: 415ea7f1c8cSNeel Natu uart_toggle_intr(sc); 416*e10b9d66SSHENG-YI HONG uart_softc_unlock(sc->backend); 417ea7f1c8cSNeel Natu 418ea7f1c8cSNeel Natu return (reg); 419ea7f1c8cSNeel Natu } 420ea7f1c8cSNeel Natu 421ea7f1c8cSNeel Natu int 422ea7f1c8cSNeel Natu uart_legacy_alloc(int which, int *baseaddr, int *irq) 423ea7f1c8cSNeel Natu { 424ea7f1c8cSNeel Natu 425ed721684SMark Johnston if (which < 0 || which >= (int)UART_NLDEVS || uart_lres[which].inuse) 426ea7f1c8cSNeel Natu return (-1); 427ea7f1c8cSNeel Natu 428ea7f1c8cSNeel Natu uart_lres[which].inuse = true; 429ea7f1c8cSNeel Natu *baseaddr = uart_lres[which].baseaddr; 430ea7f1c8cSNeel Natu *irq = uart_lres[which].irq; 431ea7f1c8cSNeel Natu 432ea7f1c8cSNeel Natu return (0); 433ea7f1c8cSNeel Natu } 434ea7f1c8cSNeel Natu 435d1c5d0cfSMark Johnston struct uart_ns16550_softc * 436d1c5d0cfSMark Johnston uart_ns16550_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 437ea7f1c8cSNeel Natu void *arg) 438ea7f1c8cSNeel Natu { 439d1c5d0cfSMark Johnston struct uart_ns16550_softc *sc; 440ea7f1c8cSNeel Natu 441d1c5d0cfSMark Johnston sc = calloc(1, sizeof(struct uart_ns16550_softc)); 442ea7f1c8cSNeel Natu 443ea7f1c8cSNeel Natu sc->arg = arg; 444ea7f1c8cSNeel Natu sc->intr_assert = intr_assert; 445ea7f1c8cSNeel Natu sc->intr_deassert = intr_deassert; 446d1c5d0cfSMark Johnston sc->backend = uart_init(); 447ea7f1c8cSNeel Natu 448ea7f1c8cSNeel Natu uart_reset(sc); 449ea7f1c8cSNeel Natu 450ea7f1c8cSNeel Natu return (sc); 451ea7f1c8cSNeel Natu } 452ea7f1c8cSNeel Natu 453ea7f1c8cSNeel Natu int 454d1c5d0cfSMark Johnston uart_ns16550_tty_open(struct uart_ns16550_softc *sc, const char *device) 455ea7f1c8cSNeel Natu { 456d1c5d0cfSMark Johnston return (uart_tty_open(sc->backend, device, uart_drain, sc)); 457ea7f1c8cSNeel Natu } 458483d953aSJohn Baldwin 459483d953aSJohn Baldwin #ifdef BHYVE_SNAPSHOT 460483d953aSJohn Baldwin int 461d1c5d0cfSMark Johnston uart_ns16550_snapshot(struct uart_ns16550_softc *sc, 462d1c5d0cfSMark Johnston struct vm_snapshot_meta *meta) 463483d953aSJohn Baldwin { 464483d953aSJohn Baldwin int ret; 465483d953aSJohn Baldwin 466483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->data, meta, ret, done); 467483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->ier, meta, ret, done); 468483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->lcr, meta, ret, done); 469483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->mcr, meta, ret, done); 470483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->lsr, meta, ret, done); 471483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->msr, meta, ret, done); 472483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->fcr, meta, ret, done); 473483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->scr, meta, ret, done); 474483d953aSJohn Baldwin 475483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->dll, meta, ret, done); 476483d953aSJohn Baldwin SNAPSHOT_VAR_OR_LEAVE(sc->dlh, meta, ret, done); 477483d953aSJohn Baldwin 478d1c5d0cfSMark Johnston ret = uart_rxfifo_snapshot(sc->backend, meta); 479483d953aSJohn Baldwin 480483d953aSJohn Baldwin sc->thre_int_pending = 1; 481483d953aSJohn Baldwin 482483d953aSJohn Baldwin done: 483483d953aSJohn Baldwin return (ret); 484483d953aSJohn Baldwin } 485483d953aSJohn Baldwin #endif 486