/* * 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); }
/* * 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); }
static void dcons_outwakeup(struct tty *tp) { struct dcons_softc *dc; char ch; dc = tty_softc(tp); while (ttydisc_getc(tp, &ch, sizeof ch) != 0) dcons_os_putc(dc, ch); }
static void uart_phyp_ttyoutwakeup(struct tty *tp) { struct uart_phyp_softc *sc; char buffer[8]; int len; sc = tty_softc(tp); while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0) uart_phyp_put(sc, buffer, len); }
static void mambotty_outwakeup(struct tty *tp) { int len; u_char buf[MAMBOBURSTLEN]; for (;;) { len = ttydisc_getc(tp, buf, sizeof buf); if (len == 0) break; mambocall(MAMBO_CONSOLE_WRITE, buf, (register_t)len, 1UL); } }
static void ofwtty_outwakeup(struct tty *tp) { int len; u_char buf[OFBURSTLEN]; for (;;) { len = ttydisc_getc(tp, buf, sizeof buf); if (len == 0) break; OF_write(stdout, buf, len); } }
static void xcoutwakeup(struct tty *tp) { boolean_t cons_full = FALSE; char c; while (ttydisc_getc(tp, &c, 1) == 1 && !cons_full) cons_full = xcons_putc(c); if (cons_full) { /* let the timeout kick us in a bit */ xc_start_needed = TRUE; } }
static void nmdm_task_tty(void *arg, int pending __unused) { struct tty *tp, *otp; struct nmdmpart *np = arg; char c; tp = np->np_tty; tty_lock(tp); if (tty_gone(tp)) { tty_unlock(tp); return; } otp = np->np_other->np_tty; KASSERT(otp != NULL, ("NULL otp in nmdmstart")); KASSERT(otp != tp, ("NULL otp == tp nmdmstart")); if (np->np_other->np_dcd) { if (!tty_opened(tp)) { np->np_other->np_dcd = 0; ttydisc_modem(otp, 0); } } else { if (tty_opened(tp)) { np->np_other->np_dcd = 1; ttydisc_modem(otp, 1); } } /* This may happen when we are in detach process. */ if (tty_gone(otp)) { tty_unlock(otp); return; } while (ttydisc_rint_poll(otp) > 0) { if (np->np_rate && !np->np_quota) break; if (ttydisc_getc(tp, &c, 1) != 1) break; np->np_quota--; ttydisc_rint(otp, c, 0); } ttydisc_rint_done(otp); tty_unlock(tp); }
static void bvm_tty_outwakeup(struct tty *tp) { int len, written; u_char buf[BVMBURSTLEN]; for (;;) { len = ttydisc_getc(tp, buf, sizeof(buf)); if (len == 0) break; written = 0; while (written < len) bvm_wcons(buf[written++]); } }
/*------------------------------------------------------------------------* * ucom_get_data * * Return values: * 0: No data is available. * Else: Data is available. *------------------------------------------------------------------------*/ uint8_t ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen) { struct usb_page_search res; struct tty *tp = sc->sc_tty; uint32_t cnt; uint32_t offset_orig; mtx_assert(sc->sc_mtx, MA_OWNED); if (tty_gone(tp) || !(sc->sc_flag & UCOM_FLAG_GP_DATA)) { actlen[0] = 0; return (0); /* multiport device polling */ } offset_orig = offset; while (len != 0) { usbd_get_page(pc, offset, &res); if (res.length > len) { res.length = len; } /* copy data directly into USB buffer */ cnt = ttydisc_getc(tp, res.buffer, res.length); offset += cnt; len -= cnt; if (cnt < res.length) { /* end of buffer */ break; } } actlen[0] = offset - offset_orig; DPRINTF("cnt=%d\n", actlen[0]); if (actlen[0] == 0) { return (0); } return (1); }
static void cfe_tty_outwakeup(struct tty *tp) { int len, written, rc; u_char buf[CFEBURSTLEN]; for (;;) { len = ttydisc_getc(tp, buf, sizeof buf); if (len == 0) break; written = 0; while (written < len) { rc = cfe_write(conhandle, &buf[written], len - written); if (rc < 0) break; written += rc; } } }
static void hvcn_outwakeup(struct tty *tp) { for (;;) { /* Refill the input buffer. */ if (buflen == 0) { buflen = ttydisc_getc(tp, buf, PCBURST); bufindex = 0; } /* Transmit the input buffer. */ while (buflen) { if (hv_cons_putchar(buf[bufindex]) == H_EWOULDBLOCK) return; bufindex++; buflen--; } } }
static void uart_tty_outwakeup(struct tty *tp) { struct uart_softc *sc; sc = tty_softc(tp); if (sc == NULL || sc->sc_leaving) return; if (sc->sc_txbusy) return; /* * Respect RTS/CTS (output) flow control if enabled and not already * handled by hardware. */ if ((tp->t_termios.c_cflag & CCTS_OFLOW) && !sc->sc_hwoflow && !(sc->sc_hwsig & SER_CTS)) return; sc->sc_txdatasz = ttydisc_getc(tp, sc->sc_txbuf, sc->sc_txfifosz); if (sc->sc_txdatasz != 0) UART_TRANSMIT(sc); }
/* * Nudge the transmitter... * * XXX: I inherited some funny code here. It implies the host card only * interrupts when the transmit buffer reaches the low-water-mark, and does * not interrupt when it's actually hits empty. In some cases, we have * processes waiting for complete drain, and we need to simulate an interrupt * about when we think the buffer is going to be empty (and retry if not). * I really am not certain about this... I *need* the hardware manuals. */ static void si_start(struct tty *tp) { struct si_port *pp; volatile struct si_channel *ccbp; BYTE ipos, count; #if 0 int nchar; #endif int oldspl, n, amount; oldspl = spltty(); mtx_assert(&Giant, MA_OWNED); pp = tty_softc(tp); DPRINT((pp, DBG_ENTRY|DBG_START, "si_start(%x) sp_state %x\n", tp, pp->sp_state)); ccbp = pp->sp_ccb; while ((count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos) < 255) { DPRINT((pp, DBG_START, "txbuf pend count %d\n", (BYTE)count)); ipos = (unsigned int)ccbp->hi_txipos; if ((int)ccbp->hi_txopos <= ipos) amount = SI_BUFFERSIZE - ipos; else amount = 255 - count; DPRINT((pp, DBG_START, "spaceleft amount %d\n", amount)); if (amount == 0) break; n = ttydisc_getc(tp, si_txbuf, amount); DPRINT((pp, DBG_START, "getc n=%d\n", n)); if (n == 0) break; si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); ccbp->hi_txipos += n; } #if 0 /* * See if there are any characters still to come. If so, we can * depend on si_start being called again. * * XXX the manual is vague on this. It implies we get an interrupt * when the transmit queue reaches the 25% low water mark, but NOT * when it hits empty. */ nchar = ttyoutq_getsize(&tp->t_outq) - ttyoutq_bytesleft(&tp->t_outq); DPRINT((pp, DBG_START, "count %d, nchar %d\n", (BYTE)count, nchar)); if (count != 0 && nchar == 0) { int time; /* XXX lame. Ticks per character. used to be a table. */ time = (tp->t_termios.c_ospeed + 9) / 10; if (time > 0) { if (time < nchar) time = nchar / time; else time = 2; } else { DPRINT((pp, DBG_START, "bad char time value! %d\n", time)); time = hz/10; } if ((pp->sp_state & SS_LSTART) != 0) untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); pp->sp_state |= SS_LSTART; pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); } #endif splx(oldspl); DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); }
/*------------------------------------------------------------------------* * ucom_get_data * * Return values: * 0: No data is available. * Else: Data is available. *------------------------------------------------------------------------*/ uint8_t ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen) { struct usb_page_search res; struct tty *tp = sc->sc_tty; uint32_t cnt; uint32_t offset_orig; UCOM_MTX_ASSERT(sc, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_CONSOLE) { unsigned int temp; /* get total TX length */ temp = ucom_cons_tx_high - ucom_cons_tx_low; temp %= UCOM_CONS_BUFSIZE; /* limit TX length */ if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low)) temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low); if (temp > len) temp = len; /* copy in data */ usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp); /* update counters */ ucom_cons_tx_low += temp; ucom_cons_tx_low %= UCOM_CONS_BUFSIZE; /* store actual length */ *actlen = temp; return (temp ? 1 : 0); } if (tty_gone(tp) || !(sc->sc_flag & UCOM_FLAG_GP_DATA)) { actlen[0] = 0; return (0); /* multiport device polling */ } offset_orig = offset; while (len != 0) { usbd_get_page(pc, offset, &res); if (res.length > len) { res.length = len; } /* copy data directly into USB buffer */ cnt = ttydisc_getc(tp, res.buffer, res.length); offset += cnt; len -= cnt; if (cnt < res.length) { /* end of buffer */ break; } } actlen[0] = offset - offset_orig; DPRINTF("cnt=%d\n", actlen[0]); if (actlen[0] == 0) { return (0); } return (1); }