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