/* * Send output to the UART until either there's none left to send, or we run * out of room and need to await an interrupt so that we can start sending * again. * * XXXRW: It would be nice to query WSPACE at the beginning and write to the * FIFO in bugger chunks. */ static void aju_handle_output(struct altera_jtag_uart_softc *sc, struct tty *tp) { uint32_t v; uint8_t ch; tty_lock_assert(tp, MA_OWNED); AJU_LOCK_ASSERT(sc); AJU_UNLOCK(sc); while (ttydisc_getc_poll(tp) != 0) { AJU_LOCK(sc); v = aju_control_read(sc); if ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) != 0) { AJU_UNLOCK(sc); if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch)) panic("%s: ttydisc_getc", __func__); AJU_LOCK(sc); /* * XXXRW: There is a slight race here in which we test * for writability, drop the lock, get the character * from the tty layer, re-acquire the lock, and then * write. It's possible for other code -- * specifically, the low-level console -- to have * written in the mean time, which might mean that * there is no longer space. The BERI memory bus will * cause this write to block, wedging the processor * until space is available -- which could be a while * if JTAG is not attached! * * The 'easy' fix is to drop the character if WSPACE * has become unset. Not sure what the 'hard' fix is. */ aju_data_write(sc, ch); } else { /* * If JTAG is not present, then we will drop this * character instead of perhaps scheduling an * interrupt to let us know when there is buffer * space. Otherwise we might get a write interrupt * later even though we aren't interested in sending * anymore. Loop to drain TTY-layer buffer. */ if (*sc->ajus_jtag_presentp == 0) { if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch)) panic("%s: ttydisc_getc 2", __func__); AJU_UNLOCK(sc); continue; } if (sc->ajus_irq_res != NULL) aju_intr_writable_enable(sc); return; } AJU_UNLOCK(sc); } AJU_LOCK(sc); aju_intr_writable_disable(sc); }
static char aju_read(struct altera_jtag_uart_softc *sc) { AJU_LOCK_ASSERT(sc); while (!aju_readable(sc)); *sc->ajus_buffer_validp = 0; return (*sc->ajus_buffer_datap); }
static void aju_intr_disable(struct altera_jtag_uart_softc *sc) { uint32_t v; AJU_LOCK_ASSERT(sc); v = aju_control_read(sc); v &= ~(ALTERA_JTAG_UART_CONTROL_RE | ALTERA_JTAG_UART_CONTROL_WE); aju_control_write(sc, v); }
static void aju_intr_writable_disable(struct altera_jtag_uart_softc *sc) { uint32_t v; AJU_LOCK_ASSERT(sc); atomic_add_int(&aju_intr_writable_disabled, 1); v = aju_control_read(sc); v &= ~ALTERA_JTAG_UART_CONTROL_WE; aju_control_write(sc, v); }
static inline int aju_readable(struct altera_jtag_uart_softc *sc) { uint32_t v; AJU_LOCK_ASSERT(sc); if (*sc->ajus_buffer_validp) return (1); v = aju_data_read(sc); if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) { *sc->ajus_buffer_validp = 1; *sc->ajus_buffer_datap = (v & ALTERA_JTAG_UART_DATA_DATA); return (1); } return (0); }
/* * Send output to the UART until either there's none left to send, or we run * out of room and need to await an interrupt so that we can start sending * again. * * XXXRW: It would be nice to query WSPACE at the beginning and write to the * FIFO in bugger chunks. */ static void aju_handle_output(struct altera_jtag_uart_softc *sc, struct tty *tp) { uint32_t v; uint8_t ch; tty_lock_assert(tp, MA_OWNED); AJU_LOCK_ASSERT(sc); AJU_UNLOCK(sc); while (ttydisc_getc_poll(tp) != 0) { AJU_LOCK(sc); v = aju_control_read(sc); if ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) != 0) { AJU_UNLOCK(sc); if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch)) panic("%s: ttydisc_getc", __func__); AJU_LOCK(sc); aju_data_write(sc, ch); } else { /* * If JTAG is not present, then we will drop this * character instead of perhaps scheduling an * interrupt to let us know when there is buffer * space. Otherwise we might get a write interrupt * later even though we aren't interested in sending * anymore. Loop to drain TTY-layer buffer. */ if (*sc->ajus_jtag_presentp == 0) { if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch)) panic("%s: ttydisc_getc 2", __func__); AJU_UNLOCK(sc); continue; } if (sc->ajus_irq_res != NULL) aju_intr_writable_enable(sc); return; } AJU_UNLOCK(sc); } AJU_LOCK(sc); aju_intr_writable_disable(sc); }
/* * The actual work of checking for, and handling, available reads. This is * used in both polled and interrupt-driven modes, as JTAG UARTs may be hooked * up with, or without, IRQs allocated. */ static void aju_handle_input(struct altera_jtag_uart_softc *sc, struct tty *tp) { int c; tty_lock_assert(tp, MA_OWNED); AJU_LOCK_ASSERT(sc); while (aju_readable(sc)) { c = aju_read(sc); AJU_UNLOCK(sc); #ifdef KDB if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) kdb_alt_break(c, &sc->ajus_alt_break_state); #endif ttydisc_rint(tp, c, 0); AJU_LOCK(sc); } AJU_UNLOCK(sc); ttydisc_rint_done(tp); AJU_LOCK(sc); }