PERFORCE change 34739 for review

Marcel Moolenaar marcel at FreeBSD.org
Sat Jul 19 21:55:03 PDT 2003


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

Change 34739 by marcel at marcel_nfs on 2003/07/19 21:54:47

	o  Merge uart_tty.c into uart_core.c. The seperation is just too
	   much trouble.
	o  Keep framing errors and parity errors seperate. It's not our
	   place to lose information.
	o  Further flesh-out the ns8250 driver. Both transmit and receive
	   should do something useful.
	o  Further wrap my brain around the TTY stuff. If I'm unlucky, I
	   may even decrypt sio(4).

Affected files ...

.. //depot/projects/uart/conf/files#8 edit
.. //depot/projects/uart/dev/uart/uart_bus.h#6 edit
.. //depot/projects/uart/dev/uart/uart_core.c#7 edit
.. //depot/projects/uart/dev/uart/uart_dev_ns8250.c#7 edit
.. //depot/projects/uart/dev/uart/uart_tty.c#5 delete

Differences ...

==== //depot/projects/uart/conf/files#8 (text+ko) ====

@@ -788,7 +788,6 @@
 dev/uart/uart_bus_puc.c		optional	uart puc
 dev/uart/uart_cons.c		optional	uart
 dev/uart/uart_core.c		optional	uart
-dev/uart/uart_tty.c		optional	uart
 dev/ubsec/ubsec.c	optional ubsec
 #
 # USB support

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

@@ -44,9 +44,10 @@
 #define	UART_IPEND_TXIDLE	0x0010
 
 /* Received character status bits. */
-#define	UART_STAT_BREAK		0x1000
-#define	UART_STAT_OVERRUN	0x2000
-#define	UART_STAT_PARERR	0x4000
+#define	UART_STAT_BREAK		0x0100
+#define	UART_STAT_FRAMERR	0x0200
+#define	UART_STAT_OVERRUN	0x0400
+#define	UART_STAT_PARERR	0x0800
 
 /*
  * UART class & instance (=softc)
@@ -111,6 +112,48 @@
 int uart_tty_detach(struct uart_softc *);
 void uart_tty_intr(void *arg);
 
+static __inline void
+uart_debug(struct uart_softc *sc, const char *fmt, ...)
+{
+#if defined(UART_DEBUG) || 1
+	va_list ap;
+	va_start(ap, fmt);
+	if (sc != NULL)
+		device_print_prettyname(sc->sc_dev);
+	vprintf(fmt, ap);
+	va_end(ap);
+#endif
+}
+
+/*
+ * Receive buffer operations.
+ */
+static __inline int
+uart_rx_empty(struct uart_softc *sc)
+{
+	return ((sc->sc_rxget == sc->sc_rxput) ? 1 : 0);
+}
+
+static __inline int
+uart_rx_full(struct uart_softc *sc)
+{
+	return ((sc->sc_rxput + 1 < sc->sc_rxbufsz)
+	    ? (sc->sc_rxput + 1 == sc->sc_rxget) : (sc->sc_rxget == 0));
+}
+
+static __inline int
+uart_rx_get(struct uart_softc *sc)
+{
+	int ptr, xc;
+
+	ptr = sc->sc_rxget;
+	if (ptr == sc->sc_rxput)
+		return (-1);
+	xc = sc->sc_rxbuf[ptr++];
+	sc->sc_rxget = (ptr < sc->sc_rxbufsz) ? ptr : 0;
+	return (xc);
+}
+
 static __inline int
 uart_rx_put(struct uart_softc *sc, int xc)
 {
@@ -124,17 +167,46 @@
 	return (0);
 }
 
-static __inline void
-uart_debug(struct uart_softc *sc, const char *fmt, ...)
+/*
+ * Transmit buffer operations.
+ */
+static __inline int
+uart_tx_empty(struct uart_softc *sc)
+{
+	return ((sc->sc_txget == sc->sc_txput) ? 1 : 0);
+}
+
+static __inline int
+uart_tx_full(struct uart_softc *sc)
+{
+	return ((sc->sc_txput + 1 < sc->sc_txbufsz)
+	    ? (sc->sc_txput + 1 == sc->sc_txget) : (sc->sc_txget == 0));
+}
+
+static __inline int
+uart_tx_get(struct uart_softc *sc)
+{
+	int ptr, c;
+
+	ptr = sc->sc_txget;
+	if (ptr == sc->sc_txput)
+		return (-1);
+	c = sc->sc_txbuf[ptr++];
+	sc->sc_txget = (ptr < sc->sc_txbufsz) ? ptr : 0;
+	return (c);
+}
+
+static __inline int
+uart_tx_put(struct uart_softc *sc, int c)
 {
-#if defined(UART_DEBUG) || 1
-	va_list ap;
-	va_start(ap, fmt);
-	if (sc != NULL)
-		device_print_prettyname(sc->sc_dev);
-	vprintf(fmt, ap);
-	va_end(ap);
-#endif
+	int ptr;
+
+	ptr = (sc->sc_txput + 1 < sc->sc_txbufsz) ? sc->sc_txput + 1 : 0;
+	if (ptr == sc->sc_txget)
+		return (ENOSPC);
+	sc->sc_txbuf[sc->sc_txput] = c;
+	sc->sc_txput = ptr;
+	return (0);
 }
 
 #endif /* _DEV_UART_BUS_H_ */

==== //depot/projects/uart/dev/uart/uart_core.c#7 (text+ko) ====

@@ -31,6 +31,7 @@
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/conf.h>
+#include <sys/cons.h>
 #include <sys/interrupt.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
@@ -52,6 +53,103 @@
 
 MALLOC_DEFINE(M_UART, "UART", "UART driver");
 
+static d_open_t uart_open;
+static d_close_t uart_close;
+static d_ioctl_t uart_ioctl;
+
+static struct cdevsw uart_cdevsw = {
+	.d_open = uart_open,
+	.d_close = uart_close,
+	.d_read = ttyread,
+	.d_write = ttywrite,
+	.d_ioctl = uart_ioctl,
+	.d_poll = ttypoll,
+	.d_name = uart_driver_name,
+	.d_maj = MAJOR_AUTO,
+	.d_flags = D_TTY,
+	.d_kqfilter = ttykqfilter,
+};
+
+static void
+uart_tty_oproc(struct tty *tp)
+{
+	struct uart_softc *sc;
+	int c;
+
+	sc = tp->t_dev->si_drv1;
+	if (sc == NULL || sc->sc_leaving)
+		return;
+
+	if (tp->t_state & TS_TBLOCK) {
+		/* XXX clear RTS */
+	} else {
+		/* XXX set RTS */
+	}
+
+	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
+		ttwwakeup(tp);
+		return;
+	}
+
+	while (!uart_tx_full(sc) && tp->t_outq.c_cc > 0) {
+		c = getc(&tp->t_outq);
+		uart_tx_put(sc, c);
+	}
+	tp->t_state |= TS_BUSY;
+	UART_TRANSMIT(sc);
+	ttwwakeup(tp);
+}
+
+static int
+uart_tty_param(struct tty *tp, struct termios *t)
+{
+	return (0);
+}
+
+static void
+uart_tty_stop(struct tty *tp, int rw)
+{
+	struct uart_softc *sc;
+
+	sc = tp->t_dev->si_drv1;
+	if (sc == NULL || sc->sc_leaving)
+		return;
+}
+
+void
+uart_tty_intr(void *arg)
+{
+	struct uart_softc *sc = arg;
+	struct tty *tp;
+	int c, pend, xc;
+
+	if (sc->sc_leaving)
+		return;
+
+	pend = atomic_readandclear_32(&sc->sc_ttypend);
+	if (pend == 0)
+		return;
+
+	tp = sc->sc_tty;
+
+	if (pend & UART_IPEND_RXREADY) {
+		while (!uart_rx_empty(sc)) {
+			xc = uart_rx_get(sc);
+			c = xc & 0xff;
+			if (xc & UART_STAT_FRAMERR)
+				c |= TTY_FE;
+			if (xc & UART_STAT_PARERR)
+				c |= TTY_PE;
+			(*linesw[tp->t_line].l_rint)(c, tp);
+		}
+	}
+
+	if (pend & UART_IPEND_TXIDLE) {
+		tp->t_state &= ~TS_BUSY;
+		(*linesw[tp->t_line].l_start)(tp);
+	}
+}
+
 /*
  * A break condition has been detected. We treat the break condition as
  * a special case that should not happen during normal operation. When
@@ -132,7 +230,8 @@
 {
 	if (sc->sc_txget != sc->sc_txput)
 		UART_TRANSMIT(sc);
-	atomic_set_32(&sc->sc_ttypend, UART_IPEND_TXIDLE);
+	else
+		atomic_set_32(&sc->sc_ttypend, UART_IPEND_TXIDLE);
 }
 
 static void
@@ -231,6 +330,7 @@
 {
 	struct uart_softc *sc, *sc0;
 	const char *sep;
+	struct tty *tp;
 	int error;
 
 	/*
@@ -318,13 +418,29 @@
 		printf("\n");
 	}
 
-	error = uart_tty_attach(sc);
-	if (!error)
-		return (0);
+	tp = ttymalloc(NULL);
+	sc->sc_tty = tp;
+
+	sc->sc_si = make_dev(&uart_cdevsw, device_get_unit(sc->sc_dev),
+	    UID_ROOT, GID_WHEEL, 0600, "%s%r", uart_driver_name,
+	    device_get_unit(sc->sc_dev));
+	sc->sc_si->si_drv1 = sc;
+	sc->sc_si->si_tty = tp;
+
+	tp->t_dev = sc->sc_si;
+	tp->t_oproc = uart_tty_oproc;
+	tp->t_param = uart_tty_param;
+	tp->t_stop = uart_tty_stop;
+
+	if (sc->sc_console) {
+		((struct consdev *)uart_console.consdev)->cn_dev =
+		    makedev(uart_cdevsw.d_maj, device_get_unit(sc->sc_dev));
+	}
 
-	sc->sc_leaving = 1;
+	swi_add(&tty_ithd, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
+	    INTR_TYPE_TTY, &sc->sc_softih);
 
-	UART_DETACH(sc);
+	return (0);
 
  fail:
 	free(sc->sc_txbuf, M_UART);
@@ -348,7 +464,9 @@
 
 	sc->sc_leaving = 1;
 
-	uart_tty_detach(sc);
+	ithread_remove_handler(sc->sc_softih);
+	destroy_dev(sc->sc_si);
+	/* ttyfree(sc->sc_tty); */
 
 	UART_DETACH(sc);
 
@@ -364,3 +482,74 @@
 
 	return (0);
 }
+
+static int
+uart_open(dev_t dev, int flags, int mode, struct thread *td)
+{
+	struct uart_softc *sc;
+	struct tty *tp;
+	int error;
+
+	sc = dev->si_drv1;
+	if (sc == NULL || sc->sc_leaving)
+		return (ENXIO);
+
+	tp = dev->si_tty;
+	if (tp->t_state & TS_ISOPEN) {
+		if ((tp->t_state & TS_XCLUDE) && suser(td) != 0)
+			return (EBUSY);
+	} else {
+		tp->t_cflag = TTYDEF_CFLAG;
+		tp->t_iflag = TTYDEF_IFLAG;
+		tp->t_lflag = TTYDEF_LFLAG;
+		tp->t_oflag = TTYDEF_OFLAG;
+		if (sc->sc_console) {
+			tp->t_cflag |= CLOCAL;
+			tp->t_ispeed = tp->t_ospeed = uart_console.baudrate;
+		} else
+			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+	}
+
+	error = (*linesw[tp->t_line].l_open)(dev, tp);
+	return (error);
+}
+
+static int
+uart_close(dev_t dev, int flags, int mode, struct thread *td)
+{
+	struct tty *tp;
+
+	tp = dev->si_tty;
+
+	if (!(tp->t_state & TS_ISOPEN))
+		return (0);
+
+	/* XXX reset UART line and modem signals. */
+
+	(*linesw[tp->t_line].l_close)(tp, flags);
+	ttyclose(tp);
+	return (0);
+}
+
+static int
+uart_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
+{
+	struct uart_softc *sc;
+	struct tty *tp;
+	int error;
+
+	tp = dev->si_tty;
+	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, td);
+	if (error != ENOIOCTL)
+		return (error);
+
+	error = ttioctl(tp, cmd, data, flags);
+	if (error != ENOIOCTL)
+		return (error);
+
+	sc = dev->si_drv1;
+	if (sc == NULL || sc->sc_leaving)
+		return (ENXIO);
+
+	return (ENOTTY);
+}

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

@@ -529,13 +529,40 @@
 static int
 ns8250_bus_receive(struct uart_softc *sc)
 {
+	struct uart_bas *bas;
+	int ptr, xc;
+	uint8_t lsr;
+
+	bas = &sc->sc_bas;
 
-	return (0);
+	while (!uart_rx_full(sc)) {
+		lsr = uart_getreg(bas, REG_LSR);
+		if ((lsr & LSR_RXRDY) == 0)
+			break;
+		xc = uart_getreg(bas, REG_DATA);
+		if (lsr & LSR_FE)
+			xc |= UART_STAT_FRAMERR;
+		if (lsr & LSR_PE)
+			xc |= UART_STAT_PARERR;
+		uart_rx_put(sc, xc);
+	}
+ 	return (0);
 }
 
 static int
 ns8250_bus_transmit(struct uart_softc *sc)
 {
+	struct uart_bas *bas;
+	int xc;
+
+	bas = &sc->sc_bas;
 
+	while (!uart_tx_empty(sc)) {
+		if ((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0)
+			break;
+		xc = uart_tx_get(sc);
+		uart_setreg(bas, REG_DATA, xc);
+		uart_barrier(bas);
+	}
 	return (0);
 }


More information about the p4-projects mailing list