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