2 * Copyright (c) 2012 NetApp, Inc.
3 * Copyright (c) 2013 Neel Natu <neel@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/types.h>
34 #include <dev/ic/ns16550.h>
46 #include "uart_emul.h"
48 #define COM1_BASE 0x3F8
50 #define COM2_BASE 0x2F8
53 #define DEFAULT_RCLK 1843200
54 #define DEFAULT_BAUD 9600
56 #define FCR_RX_MASK 0xC0
61 #define MSR_DELTA_MASK 0x0f
64 #define REG_SCR com_scr
69 static bool uart_stdio; /* stdio in use for i/o */
76 { COM1_BASE, COM1_IRQ, false},
77 { COM2_BASE, COM2_IRQ, false},
80 #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0]))
84 int rindex; /* index to read from */
85 int windex; /* index to write to */
86 int num; /* number of characters in the fifo */
87 int size; /* size of the fifo */
91 pthread_mutex_t mtx; /* protects all softc elements */
92 uint8_t data; /* Data register (R/W) */
93 uint8_t ier; /* Interrupt enable register (R/W) */
94 uint8_t lcr; /* Line control register (R/W) */
95 uint8_t mcr; /* Modem control register (R/W) */
96 uint8_t lsr; /* Line status register (R/W) */
97 uint8_t msr; /* Modem status register (R/W) */
98 uint8_t fcr; /* FIFO control register (W) */
99 uint8_t scr; /* Scratch register (R/W) */
101 uint8_t dll; /* Baudrate divisor latch LSB */
102 uint8_t dlh; /* Baudrate divisor latch MSB */
108 bool thre_int_pending; /* THRE interrupt pending */
111 uart_intr_func_t intr_assert;
112 uart_intr_func_t intr_deassert;
115 static void uart_drain(int fd, enum ev_type ev, void *arg);
117 static struct termios tio_orig, tio_new; /* I/O Terminals */
123 tcsetattr(STDIN_FILENO, TCSANOW, &tio_orig);
130 tcgetattr(STDIN_FILENO, &tio_orig);
133 tcsetattr(STDIN_FILENO, TCSANOW, &tio_new);
139 tty_char_available(void)
145 FD_SET(STDIN_FILENO, &rfds);
148 if (select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv) > 0 ) {
160 if (tty_char_available()) {
161 read(STDIN_FILENO, &rb, 1);
169 ttywrite(unsigned char wb)
172 (void)write(STDIN_FILENO, &wb, 1);
176 fifo_reset(struct fifo *fifo, int size)
179 bzero(fifo, sizeof(struct fifo));
184 fifo_putchar(struct fifo *fifo, uint8_t ch)
187 if (fifo->num < fifo->size) {
188 fifo->buf[fifo->windex] = ch;
189 fifo->windex = (fifo->windex + 1) % fifo->size;
197 fifo_getchar(struct fifo *fifo)
202 c = fifo->buf[fifo->rindex];
203 fifo->rindex = (fifo->rindex + 1) % fifo->size;
211 fifo_numchars(struct fifo *fifo)
218 fifo_available(struct fifo *fifo)
221 return (fifo->num < fifo->size);
225 uart_opentty(struct uart_softc *sc)
229 assert(!sc->opened && sc->stdio);
232 mev = mevent_add(STDIN_FILENO, EVF_READ, uart_drain, sc);
237 * The IIR returns a prioritized interrupt reason:
238 * - receive data available
239 * - transmit holding register empty
240 * - modem status change
242 * Return an interrupt reason if one is available.
245 uart_intr_reason(struct uart_softc *sc)
248 if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0)
250 else if (fifo_numchars(&sc->rxfifo) > 0 && (sc->ier & IER_ERXRDY) != 0)
252 else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0)
254 else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0)
261 uart_reset(struct uart_softc *sc)
265 divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16;
267 sc->dlh = divisor >> 16;
269 fifo_reset(&sc->rxfifo, 1); /* no fifo until enabled by software */
273 * Toggle the COM port's intr pin depending on whether or not we have an
274 * interrupt condition to report to the processor.
277 uart_toggle_intr(struct uart_softc *sc)
281 intr_reason = uart_intr_reason(sc);
283 if (intr_reason == IIR_NOPEND)
284 (*sc->intr_deassert)(sc->arg);
286 (*sc->intr_assert)(sc->arg);
290 uart_drain(int fd, enum ev_type ev, void *arg)
292 struct uart_softc *sc;
297 assert(fd == STDIN_FILENO);
298 assert(ev == EVF_READ);
301 * This routine is called in the context of the mevent thread
302 * to take out the softc lock to protect against concurrent
303 * access from a vCPU i/o exit
305 pthread_mutex_lock(&sc->mtx);
307 if ((sc->mcr & MCR_LOOPBACK) != 0) {
310 while (fifo_available(&sc->rxfifo) &&
311 ((ch = ttyread()) != -1)) {
312 fifo_putchar(&sc->rxfifo, ch);
314 uart_toggle_intr(sc);
317 pthread_mutex_unlock(&sc->mtx);
321 uart_write(struct uart_softc *sc, int offset, uint8_t value)
327 if (!sc->opened && sc->stdio) {
332 pthread_mutex_lock(&sc->mtx);
335 * Take care of the special case DLAB accesses first
337 if ((sc->lcr & LCR_DLAB) != 0) {
338 if (offset == REG_DLL) {
343 if (offset == REG_DLH) {
351 if (sc->mcr & MCR_LOOPBACK) {
352 if (fifo_putchar(&sc->rxfifo, value) != 0)
354 } else if (sc->stdio) {
356 } /* else drop on floor */
357 sc->thre_int_pending = true;
361 * Apply mask so that bits 4-7 are 0
362 * Also enables bits 0-3 only if they're 1
364 sc->ier = value & 0x0F;
368 * When moving from FIFO and 16450 mode and vice versa,
369 * the FIFO contents are reset.
371 if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) {
372 fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1;
373 fifo_reset(&sc->rxfifo, fifosz);
377 * The FCR_ENABLE bit must be '1' for the programming
378 * of other FCR bits to be effective.
380 if ((value & FCR_ENABLE) == 0) {
383 if ((value & FCR_RCV_RST) != 0)
384 fifo_reset(&sc->rxfifo, FIFOSZ);
387 (FCR_ENABLE | FCR_DMA | FCR_RX_MASK);
394 /* Apply mask so that bits 5-7 are 0 */
395 sc->mcr = value & 0x1F;
398 if (sc->mcr & MCR_LOOPBACK) {
400 * In the loopback mode certain bits from the
401 * MCR are reflected back into MSR
403 if (sc->mcr & MCR_RTS)
405 if (sc->mcr & MCR_DTR)
407 if (sc->mcr & MCR_OUT1)
409 if (sc->mcr & MCR_OUT2)
414 * Detect if there has been any change between the
415 * previous and the new value of MSR. If there is
416 * then assert the appropriate MSR delta bit.
418 if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS))
420 if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR))
422 if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD))
424 if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0)
428 * Update the value of MSR while retaining the delta
431 sc->msr &= MSR_DELTA_MASK;
436 * Line status register is not meant to be written to
437 * during normal operation.
442 * As far as I can tell MSR is a read-only register.
453 uart_toggle_intr(sc);
454 pthread_mutex_unlock(&sc->mtx);
458 uart_read(struct uart_softc *sc, int offset)
460 uint8_t iir, intr_reason, reg;
463 if (!sc->opened && sc->stdio) {
468 pthread_mutex_lock(&sc->mtx);
471 * Take care of the special case DLAB accesses first
473 if ((sc->lcr & LCR_DLAB) != 0) {
474 if (offset == REG_DLL) {
479 if (offset == REG_DLH) {
487 reg = fifo_getchar(&sc->rxfifo);
493 iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0;
495 intr_reason = uart_intr_reason(sc);
498 * Deal with side effects of reading the IIR register
500 if (intr_reason == IIR_TXRDY)
501 sc->thre_int_pending = false;
514 /* Transmitter is always ready for more data */
515 sc->lsr |= LSR_TEMT | LSR_THRE;
517 /* Check for new receive data */
518 if (fifo_numchars(&sc->rxfifo) > 0)
519 sc->lsr |= LSR_RXRDY;
521 sc->lsr &= ~LSR_RXRDY;
525 /* The LSR_OE bit is cleared on LSR read */
530 * MSR delta bits are cleared on read
533 sc->msr &= ~MSR_DELTA_MASK;
544 uart_toggle_intr(sc);
545 pthread_mutex_unlock(&sc->mtx);
551 uart_legacy_alloc(int which, int *baseaddr, int *irq)
554 if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse)
557 uart_lres[which].inuse = true;
558 *baseaddr = uart_lres[which].baseaddr;
559 *irq = uart_lres[which].irq;
565 uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert,
568 struct uart_softc *sc;
570 sc = malloc(sizeof(struct uart_softc));
571 bzero(sc, sizeof(struct uart_softc));
574 sc->intr_assert = intr_assert;
575 sc->intr_deassert = intr_deassert;
577 pthread_mutex_init(&sc->mtx, NULL);
585 uart_set_backend(struct uart_softc *sc, const char *opts)
588 * XXX one stdio backend supported at this time.
593 if (strcmp("stdio", opts) == 0 && !uart_stdio) {