Date: Sat, 19 Jul 2003 21:55:00 -0700 (PDT) From: Marcel Moolenaar <marcel@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 34739 for review Message-ID: <200307200455.h6K4t0c9088159@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=34739 Change 34739 by marcel@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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200307200455.h6K4t0c9088159>