Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Sep 2003 02:46:06 -0700 (PDT)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 37439 for review
Message-ID:  <200309030946.h839k6VT068477@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=37439

Change 37439 by marcel@marcel_nfs on 2003/09/03 02:45:48

	Implement flow control. Note that none of the hardware
	drivers report that they have hardware support for
	flow control, so it's all software based for now. The
	logic is there to set hardware flow control...

Affected files ...

.. //depot/projects/uart/dev/uart/uart_tty.c#12 edit

Differences ...

==== //depot/projects/uart/dev/uart/uart_tty.c#12 (text+ko) ====

@@ -160,22 +160,36 @@
 	if (sc == NULL || sc->sc_leaving)
 		return;
 
-	if (tp->t_state & TS_TBLOCK)
-		UART_SETSIG(sc, UART_SIG_DRTS);
-	else
-		UART_SETSIG(sc, UART_SIG_DRTS|UART_SIG_RTS);
+	/*
+	 * Handle input flow control. Note that if we have hardware support,
+	 * we don't do anything here. We continue to receive until our buffer
+	 * is full. At that time we cannot empty the UART itself and it will
+	 * de-assert RTS for us. In that situation we're completely stuffed.
+	 * Without hardware support, we need to toggle RTS ourselves.
+	 */
+	if ((tp->t_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) {
+		if ((tp->t_state & TS_TBLOCK) &&
+		    (sc->sc_hwsig & UART_SIG_RTS))
+			UART_SETSIG(sc, UART_SIG_DRTS);
+		else if (!(tp->t_state & TS_TBLOCK) &&
+		    !(sc->sc_hwsig & UART_SIG_RTS))
+			UART_SETSIG(sc, UART_SIG_DRTS|UART_SIG_RTS);
+	}
+
+	if (tp->t_state & TS_TTSTOP)
+		return;
+
+	if ((tp->t_state & TS_BUSY) || sc->sc_txbusy)
+		return;
 
-	if (tp->t_state & (TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) {
+	if (tp->t_outq.c_cc == 0) {
 		ttwwakeup(tp);
 		return;
 	}
 
-	if (tp->t_outq.c_cc > 0 && !sc->sc_txbusy) {
-		sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf,
-		    sc->sc_txfifosz);
-		tp->t_state |= TS_BUSY;
-		UART_TRANSMIT(sc);
-	}
+	sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf, sc->sc_txfifosz);
+	tp->t_state |= TS_BUSY;
+	UART_TRANSMIT(sc);
 	ttwwakeup(tp);
 }
 
@@ -215,8 +229,17 @@
 		parity = UART_PARITY_NONE;
 	UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity);
 	UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DTR);
-	if ((t->c_cflag & CRTS_IFLOW) == 0)
-		UART_SETSIG(sc, UART_SIG_DRTS | UART_SIG_RTS);
+	/* Set input flow control state. */
+	if (!sc->sc_hwiflow) {
+		if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK))
+			UART_SETSIG(sc, UART_SIG_DRTS);
+		else
+			UART_SETSIG(sc, UART_SIG_DRTS | UART_SIG_RTS);
+	} else
+		UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
+	/* Set output flow control state. */
+	if (sc->sc_hwoflow)
+		UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
 	ttsetwater(tp);
 	return (0);
 }
@@ -260,7 +283,7 @@
 	tp = sc->sc_u.u_tty.tp;
 
 	if (pend & UART_IPEND_RXREADY) {
-		while (!uart_rx_empty(sc)) {
+		while (!uart_rx_empty(sc) && !(tp->t_state & TS_TBLOCK)) {
 			xc = uart_rx_get(sc);
 			c = xc & 0xff;
 			if (xc & UART_STAT_FRAMERR)
@@ -280,6 +303,14 @@
 		sig = pend & UART_IPEND_SIGMASK;
 		if (sig & UART_SIG_DDCD)
 			(*linesw[tp->t_line].l_modem)(tp, sig & UART_SIG_DCD);
+		if ((sig & UART_SIG_DCTS) && (tp->t_cflag & CCTS_OFLOW) &&
+		    !sc->sc_hwoflow) {
+			if (sig & UART_SIG_CTS) {
+				tp->t_state &= ~TS_TTSTOP;
+				(*linesw[tp->t_line].l_start)(tp);
+			} else
+				tp->t_state |= TS_TTSTOP;
+		}
 	}
 
 	if (pend & UART_IPEND_TXIDLE) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200309030946.h839k6VT068477>