PERFORCE change 34914 for review

Marcel Moolenaar marcel at FreeBSD.org
Wed Jul 23 20:26:25 PDT 2003


http://perforce.freebsd.org/chv.cgi?CH=34914

Change 34914 by marcel at marcel_nfs on 2003/07/23 20:26:07

	Further improve on the ns8250 driver:
	o  Don't use the IIR register to figure out the cause of an
	   interrupt. Instead, use the LSR to get a bitmap of the
	   things that need attention. This avoids that we lose
	   pending interrupt conditions while we talk to the UART.
	   This fixes the lost transmit interrupts.
	o  Differentiate between flushing and draining. Flushing
	   implies losing data. Draining means that we wait for
	   all data to be processed. Do not yet add a drain method.
	o  Implement the getsig method. Don't depend on the delta
	   bits that the UART maintains. Do it ourselves. This is
	   mostly alpha code. We also need a setsig method to set
	   modem signals.

Affected files ...

.. //depot/projects/uart/dev/uart/uart_bus.h#7 edit
.. //depot/projects/uart/dev/uart/uart_dev_ns8250.c#8 edit

Differences ...

==== //depot/projects/uart/dev/uart/uart_bus.h#7 (text+ko) ====

@@ -32,9 +32,11 @@
 #include <sys/systm.h>
 #include <machine/stdarg.h>
 
-/* Flush targets. */
-#define	UART_FLUSH_RECEIVER	0x0001
-#define	UART_FLUSH_TRANSMITTER	0x0002
+/* Drain and flush targets. */
+#define	UART_DRAIN_RECEIVER	0x0001
+#define	UART_DRAIN_TRANSMITTER	0x0002
+#define	UART_FLUSH_RECEIVER	UART_DRAIN_RECEIVER
+#define	UART_FLUSH_TRANSMITTER	UART_DRAIN_TRANSMITTER
 
 /* Interrupt sources (in priority order). See also uart_core.c */
 #define	UART_IPEND_OVERRUN	0x0001

==== //depot/projects/uart/dev/uart/uart_dev_ns8250.c#8 (text+ko) ====

@@ -83,13 +83,13 @@
 }
 
 static int
-ns8250_flush(struct uart_bas *bas, int what)
+ns8250_drain(struct uart_bas *bas, int what)
 {
 	int delay, limit;
 
 	delay = ns8250_delay(bas);
 
-	if (what & UART_FLUSH_TRANSMITTER) {
+	if (what & UART_DRAIN_TRANSMITTER) {
 		/*
 		 * Pick an arbitrary high limit to avoid getting stuck in
 		 * an infinite loop when the hardware is broken. Make the
@@ -104,7 +104,7 @@
 		}
 	}
 
-	if (what & UART_FLUSH_RECEIVER) {
+	if (what & UART_DRAIN_RECEIVER) {
 		/*
 		 * Pick an arbitrary high limit to avoid getting stuck in
 		 * an infinite loop when the hardware is broken. Make the
@@ -129,6 +129,24 @@
 }
 
 /*
+ * We can only flush UARTs with FIFOs. UARTs without FIFOs should be
+ * drained.
+ */
+static void
+ns8250_flush(struct uart_bas *bas, int what)
+{
+	uint8_t fcr;
+
+	fcr = FCR_ENABLE;
+	if (what & UART_FLUSH_TRANSMITTER)
+		fcr |= FCR_XMT_RST;
+	if (what & UART_FLUSH_RECEIVER)
+		fcr |= FCR_RCV_RST;
+	uart_setreg(bas, REG_FCR, fcr);
+	uart_barrier(bas);
+}
+
+/*
  * Low-level UART interface.
  */
 static int ns8250_probe(struct uart_bas *bas);
@@ -299,6 +317,8 @@
 	uint8_t		fcr;
 	uint8_t		lcr;
 	uint8_t		mcr;
+	uint8_t		signals;
+	uint8_t		sigchg;
 };
 
 static int ns8250_bus_attach(struct uart_softc *);
@@ -345,6 +365,8 @@
 	uart_setreg(bas, REG_IER,
 	    IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC);
 	uart_barrier(bas);
+	ns8250->signals = uart_getreg(bas, REG_MSR) >> 4;
+	ns8250->sigchg = 0;
 	return (0);
 }
 
@@ -359,40 +381,50 @@
 ns8250_bus_flush(struct uart_softc *sc, int what)
 {
 
-	return (ns8250_flush(&sc->sc_bas, what));
+	if (sc->sc_hasfifo) {
+		ns8250_flush(&sc->sc_bas, what);
+		return (0);
+	}
+	return (ns8250_drain(&sc->sc_bas, what));
 }
 
 static int
 ns8250_bus_getsig(struct uart_softc *sc)
 {
+	struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
+	struct uart_bas *bas;
+	uint8_t sig;
 
-	return (0);
+	bas = &sc->sc_bas;
+	sig = uart_getreg(bas, REG_MSR) >> 4;
+	ns8250->sigchg |= ns8250->signals ^ sig;
+	ns8250->signals = sig;
+	return ((ns8250->sigchg << 4) | ns8250->signals);
 }
 
 static int
 ns8250_bus_ipend(struct uart_softc *sc)
 {
+	struct ns8250_softc *ns8250 = (struct ns8250_softc*)sc;
 	struct uart_bas *bas;
 	int ipend;
-	uint8_t iir, lsr;
+	uint8_t lsr, sig;
 
 	bas = &sc->sc_bas;
 	ipend = 0;
-	iir = uart_getreg(bas, REG_IIR);
-	if (iir == IIR_RLS) {
-		lsr = uart_getreg(bas, REG_LSR);
-		if (lsr & LSR_OE)
-			ipend |= UART_IPEND_OVERRUN;
-		if (lsr & LSR_BI)
-			ipend |= UART_IPEND_BREAK;
-		uart_barrier(bas);
-		iir = uart_getreg(bas, REG_IIR);
-	}
-	if (iir == IIR_RXRDY || iir == IIR_RXTOUT)
+	lsr = uart_getreg(bas, REG_LSR);
+	if (lsr & LSR_OE)
+		ipend |= UART_IPEND_OVERRUN;
+	if (lsr & LSR_BI)
+		ipend |= UART_IPEND_BREAK;
+	if (lsr & LSR_RXRDY)
 		ipend |= UART_IPEND_RXREADY;
-	if (iir == IIR_TXRDY)
+	if (lsr & LSR_TEMT)
 		ipend |= UART_IPEND_TXIDLE;
-	if (iir == IIR_MLSC)
+	sig = uart_getreg(bas, REG_MSR) >> 4;
+	ns8250->sigchg |= ns8250->signals ^ sig;
+	ns8250->signals = sig;
+	if (ns8250->sigchg)
 		ipend |= UART_IPEND_SIGCHG;
 	return (ipend);
 }
@@ -417,7 +449,7 @@
 	} else
 		mcr |= MCR_DTR | MCR_RTS;
 
-	error = ns8250_flush(bas, UART_FLUSH_TRANSMITTER);
+	error = ns8250_drain(bas, UART_DRAIN_TRANSMITTER);
 	if (error)
 		return (error);
 
@@ -458,8 +490,8 @@
 	count = 0;
 	delay = ns8250_delay(bas);
 
-	/* We have FIFOs. Flush the transmitter and receiver. */
-	error = ns8250_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
+	/* We have FIFOs. Drain the transmitter and receiver. */
+	error = ns8250_drain(bas, UART_DRAIN_RECEIVER|UART_DRAIN_TRANSMITTER);
 	if (error) {
 		uart_setreg(bas, REG_MCR, mcr);
 		uart_setreg(bas, REG_FCR, 0);
@@ -499,8 +531,7 @@
 	uart_setreg(bas, REG_MCR, mcr);
 
 	/* Reset FIFOs. */
-	uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_XMT_RST | FCR_RCV_RST);
-	uart_barrier(bas);
+	ns8250_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
 
  describe:
 	if (count >= 14 && count < 16) {
@@ -530,7 +561,7 @@
 ns8250_bus_receive(struct uart_softc *sc)
 {
 	struct uart_bas *bas;
-	int ptr, xc;
+	int xc;
 	uint8_t lsr;
 
 	bas = &sc->sc_bas;


More information about the p4-projects mailing list