/* * 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")); }
/* * 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; struct clist *qp; BYTE ipos; int nchar; int oldspl, count, n, amount, buffer_full; oldspl = spltty(); qp = &tp->t_outq; pp = tp->t_sc; DPRINT((pp, DBG_ENTRY|DBG_START, "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", tp, tp->t_state, pp->sp_state, qp->c_cc)); if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) goto out; buffer_full = 0; ccbp = pp->sp_ccb; count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); while ((nchar = qp->c_cc) > 0) { if ((BYTE)count >= 255) { buffer_full++; break; } amount = min(nchar, (255 - (BYTE)count)); ipos = (unsigned int)ccbp->hi_txipos; n = q_to_b(&tp->t_outq, si_txbuf, amount); /* will it fit in one lump? */ if ((SI_BUFFERSIZE - ipos) >= n) { si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); } else { si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], SI_BUFFERSIZE - ipos); si_bcopyv(si_txbuf + (SI_BUFFERSIZE - ipos), &ccbp->hi_txbuf[0], n - (SI_BUFFERSIZE - ipos)); } ccbp->hi_txipos += n; count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; } if (count != 0 && nchar == 0) { tp->t_state |= TS_BUSY; } else { tp->t_state &= ~TS_BUSY; } /* wakeup time? */ ttwwakeup(tp); DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", (BYTE)count, nchar, tp->t_state)); if (tp->t_state & TS_BUSY) { int time; time = ttspeedtab(tp->t_ospeed, chartimes); 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|SS_INLSTART)) == SS_LSTART) { untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); } else { pp->sp_state |= SS_LSTART; } DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); } out: splx(oldspl); DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); }