diff --git a/sys/arch/hpcmips/tx/tx39icureg.h b/sys/arch/hpcmips/tx/tx39icureg.h index e858dd50e408..6552d01900ac 100644 --- a/sys/arch/hpcmips/tx/tx39icureg.h +++ b/sys/arch/hpcmips/tx/tx39icureg.h @@ -1,4 +1,4 @@ -/* $NetBSD: tx39icureg.h,v 1.1 1999/11/20 19:56:34 uch Exp $ */ +/* $NetBSD: tx39icureg.h,v 1.2 1999/12/26 17:05:28 uch Exp $ */ /* * Copyright (c) 1999, by UCHIYAMA Yasushi @@ -154,6 +154,7 @@ #define TX39_INTRSTATUS2_UARTAEMPTYINT 0x01000000 #define TX39_INTRSTATUS2_UARTADMAFULLINT 0x00800000 #define TX39_INTRSTATUS2_UARTADMAHALFINT 0x00400000 + #define TX39_INTRSTATUS2_UARTBRXINT 0x00200000 #define TX39_INTRSTATUS2_UARTBRXOVERRUNINT 0x00100000 #define TX39_INTRSTATUS2_UARTBFRAMEERRINT 0x00080000 @@ -164,6 +165,38 @@ #define TX39_INTRSTATUS2_UARTBEMPTYINT 0x00004000 #define TX39_INTRSTATUS2_UARTBDMAFULLINT 0x00002000 #define TX39_INTRSTATUS2_UARTBDMAHALFINT 0x00001000 + +#define TX39_INTRSTATUS2_UARTRXINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBRXINT : \ + TX39_INTRSTATUS2_UARTARXINT) +#define TX39_INTRSTATUS2_UARTRXOVERRUNINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBRXOVERRUNINT : \ + TX39_INTRSTATUS2_UARTARXOVERRUNINT) +#define TX39_INTRSTATUS2_UARTFRAMEERRINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBFRAMEERRINT : \ + TX39_INTRSTATUS2_UARTAFRAMEERRINT) +#define TX39_INTRSTATUS2_UARTBREAKINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBBREAKINT : \ + TX39_INTRSTATUS2_UARTABREAKINT) +#define TX39_INTRSTATUS2_UARTPARITYERRINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBPARITYERRINT : \ + TX39_INTRSTATUS2_UARTAPARITYERRINT) +#define TX39_INTRSTATUS2_UARTTXINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBTXINT : \ + TX39_INTRSTATUS2_UARTATXINT) +#define TX39_INTRSTATUS2_UARTTXOVERRUNINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBTXOVERRUNINT : \ + TX39_INTRSTATUS2_UARTATXOVERRUNINT) +#define TX39_INTRSTATUS2_UARTEMPTYINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBEMPTYINT : \ + TX39_INTRSTATUS2_UARTEMPTYINT) +#define TX39_INTRSTATUS2_UARTDMAFULLINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBDMAFULLINT : \ + TX39_INTRSTATUS2_UARTADMAFULLINT) +#define TX39_INTRSTATUS2_UARTDMAHALFINT(x) \ + ((x) ? TX39_INTRSTATUS2_UARTBDMAHALFINT : \ + TX39_INTRSTATUS2_UARTADMAHALFINT) + #ifdef TX391X #define TX39_INTRSTATUS2_MBUSTXBUFAVAILINT 0x00000800 #define TX39_INTRSTATUS2_MBUSTXERRINT 0x00000400 diff --git a/sys/arch/hpcmips/tx/txcom.c b/sys/arch/hpcmips/tx/txcom.c index d2967d7b9c74..868471764dd6 100644 --- a/sys/arch/hpcmips/tx/txcom.c +++ b/sys/arch/hpcmips/tx/txcom.c @@ -1,4 +1,4 @@ -/* $NetBSD: txcom.c,v 1.2 1999/12/23 16:57:14 uch Exp $ */ +/* $NetBSD: txcom.c,v 1.3 1999/12/26 17:05:28 uch Exp $ */ /* * Copyright (c) 1999, by UCHIYAMA Yasushi @@ -30,7 +30,9 @@ #include #include +#include #include +#include #include /* tsleep/wakeup */ @@ -61,67 +63,78 @@ #define DPRINTF(arg) #endif -#define MAXBUF 16 -struct txcom_buf { - int b_cnt; - int b_in; - int b_out; - char b_buf[MAXBUF]; -}; +#define TXCOM_HW_CONSOLE 0x40 +#define TXCOM_RING_SIZE 256 /* must be a power of two! */ +#define TXCOM_RING_MASK (TXCOM_RING_SIZE - 1) -#define TXCOM_HW_CONSOLE 0x40 -struct txcom_softc { - struct device sc_dev; - struct tty *sc_tty; +struct txcom_chip { tx_chipset_tag_t sc_tc; int sc_slot; /* UARTA or UARTB */ int sc_cflag; int sc_speed; - struct txcom_buf *sc_rxbuf; - struct txcom_buf *sc_txbuf; - char **sc_msg; + int sc_swflags; int sc_hwflags; - u_int8_t *sc_tba; /* transmit buffer address */ - int sc_tbc, sc_heldtbc; /* transmit byte count */ - u_int8_t sc_rbuf; /* XXX */ - }; -volatile int com_softrxintr_scheduled; + +struct txcom_softc { + struct device sc_dev; + struct tty *sc_tty; + struct txcom_chip *sc_chip; + + u_int8_t *sc_tba; /* transmit buffer address */ + int sc_tbc; /* transmit byte count */ + int sc_heldtbc; + u_int8_t *sc_rbuf; /* receive buffer address */ + int sc_rbput; /* receive byte count */ + int sc_rbget; +}; extern struct cfdriver txcom_cd; int txcom_match __P((struct device*, struct cfdata*, void*)); void txcom_attach __P((struct device*, struct device*, void*)); -int txcom_txintr __P((void*)); -int txcom_a_rxintr __P((void*)); -int txcom_b_rxintr __P((void*)); -int txcom_overrun_intr __P((void*)); -void txcom_rxsoft __P((void*)); +int txcom_txintr __P((void*)); +int txcom_rxintr __P((void*)); +int txcom_overrun_intr __P((void*)); +int txcom_frameerr_intr __P((void*)); +int txcom_parityerr_intr __P((void*)); +int txcom_break_intr __P((void*)); + +void txcom_rxsoft __P((void*)); +void txcom_txsoft __P((void*)); + +void txcom_shutdown __P((struct txcom_softc*)); +void txcom_break __P((struct txcom_softc*, int)); +void txcom_modem __P((struct txcom_softc*, int)); +void txcomstart __P((struct tty*)); +int txcomparam __P((struct tty*, struct termios*)); + +int txcom_enable __P((struct txcom_chip*)); +void txcom_disable __P((struct txcom_chip*)); +void txcom_setmode __P((struct txcom_chip*)); +void txcom_setbaudrate __P((struct txcom_chip*)); int txcom_cngetc __P((dev_t)); void txcom_cnputc __P((dev_t, int)); -void txcom_cnpollc __P((dev_t, int)); +void txcom_cnpollc __P((dev_t, int)); + +__inline int __txcom_txbufready __P((struct txcom_chip*, int)); +__inline const char *__txcom_slotname __P((int)); -void txcomstart __P((struct tty*)); -int txcomparam __P((struct tty*, struct termios*)); cdev_decl(txcom); -/* Serial console */ -static struct consdev txcomcons = { - NULL, NULL, txcom_cngetc, txcom_cnputc, - txcom_cnpollc, NODEV, CN_NORMAL +struct consdev txcomcons = { + NULL, NULL, txcom_cngetc, txcom_cnputc, txcom_cnpollc, + NODEV, CN_NORMAL }; -static struct txcom_softc cn_sc; + +/* Serial console */ +struct txcom_chip txcom_chip; struct cfattach txcom_ca = { sizeof(struct txcom_softc), txcom_match, txcom_attach }; -int txcom_enable __P((struct txcom_softc*)); -void txcom_disable __P((struct txcom_softc*)); -void txcom_setmode __P((struct txcom_softc*)); -void txcom_setbaudrate __P((struct txcom_softc*)); - int txcom_match(parent, cf, aux) struct device *parent; @@ -142,28 +155,40 @@ txcom_attach(parent, self, aux) struct txcom_softc *sc = (void*)self; tx_chipset_tag_t tc; struct tty *tp; - - printf("\n"); + struct txcom_chip *chip; + int slot; /* Check this slot used as serial console */ - if (ua->ua_slot == cn_sc.sc_slot && - (cn_sc.sc_hwflags & TXCOM_HW_CONSOLE)) { - memcpy(&cn_sc, self, sizeof(struct device)); - memcpy(self, &cn_sc, sizeof(struct txcom_softc)); + if (ua->ua_slot == txcom_chip.sc_slot && + (txcom_chip.sc_hwflags & TXCOM_HW_CONSOLE)) { + sc->sc_chip = &txcom_chip; + } else { + if (!(sc->sc_chip = malloc(sizeof(struct txcom_chip), + M_DEVBUF, M_WAITOK))) { + printf(": can't allocate chip\n"); + return; + } + memset(sc->sc_chip, 0, sizeof(struct txcom_chip)); } - tc = sc->sc_tc = ua->ua_tc; - sc->sc_slot = ua->ua_slot; + chip = sc->sc_chip; + tc = chip->sc_tc = ua->ua_tc; + slot = chip->sc_slot = ua->ua_slot; + + if (!(sc->sc_rbuf = malloc(TXCOM_RING_SIZE, M_DEVBUF, M_WAITOK))) { + printf(": can't allocate buffer.\n"); + return; + } + memset(sc->sc_rbuf, 0, TXCOM_RING_SIZE); tp = ttymalloc(); tp->t_oproc = txcomstart; tp->t_param = txcomparam; tp->t_hwiflow = NULL; sc->sc_tty = tp; - cn_sc.sc_tty = tp; tty_attach(tp); - if (ISSET(sc->sc_hwflags, TXCOM_HW_CONSOLE)) { + if (ISSET(chip->sc_hwflags, TXCOM_HW_CONSOLE)) { int maj; /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) @@ -172,83 +197,95 @@ txcom_attach(parent, self, aux) cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); - printf("%s: console\n", sc->sc_dev.dv_xname); + printf(": console"); } + printf("\n"); /* * Enable interrupt */ - switch (sc->sc_slot) { - case TX39_UARTA: - tx_intr_establish(tc, MAKEINTR(2, - TX39_INTRSTATUS2_UARTARXINT), - IST_EDGE, IPL_TTY, - txcom_a_rxintr, sc); - tx_intr_establish( - tc, MAKEINTR(2, TX39_INTRSTATUS2_UARTARXOVERRUNINT), - IST_EDGE, IPL_TTY, txcom_overrun_intr, sc); - break; - case TX39_UARTB: - tx_intr_establish(tc, MAKEINTR(2, - TX39_INTRSTATUS2_UARTBRXINT), - IST_EDGE, IPL_TTY, - txcom_b_rxintr, sc); - tx_intr_establish( - tc, MAKEINTR(2, TX39_INTRSTATUS2_UARTBRXOVERRUNINT), - IST_EDGE, IPL_TTY, txcom_overrun_intr, sc); - break; - } +#define TXCOMINTR(i, s) MAKEINTR(2, TX39_INTRSTATUS2_UART##i##INT(s)) + + tx_intr_establish(tc, TXCOMINTR(RX, slot), IST_EDGE, IPL_TTY, + txcom_rxintr, sc); + tx_intr_establish(tc, TXCOMINTR(TX, slot), IST_EDGE, IPL_TTY, + txcom_txintr, sc); + tx_intr_establish(tc, TXCOMINTR(RXOVERRUN, slot), IST_EDGE, IPL_TTY, + txcom_overrun_intr, sc); + tx_intr_establish(tc, TXCOMINTR(TXOVERRUN, slot), IST_EDGE, IPL_TTY, + txcom_overrun_intr, sc); + tx_intr_establish(tc, TXCOMINTR(FRAMEERR, slot), IST_EDGE, IPL_TTY, + txcom_frameerr_intr, sc); + tx_intr_establish(tc, TXCOMINTR(PARITYERR, slot), IST_EDGE, IPL_TTY, + txcom_parityerr_intr, sc); + tx_intr_establish(tc, TXCOMINTR(BREAK, slot), IST_EDGE, IPL_TTY, + txcom_break_intr, sc); } int -txcom_enable(sc) - struct txcom_softc *sc; +txcom_enable(chip) + struct txcom_chip *chip; { tx_chipset_tag_t tc; + txreg_t reg; - int slot; + int slot, ofs, timeout; - tc = sc->sc_tc; - slot = sc->sc_slot; + tc = chip->sc_tc; + slot = chip->sc_slot; + ofs = TX39_UARTCTRL1_REG(slot); - reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot)); - /* Power */ + /* Power on */ + reg = tx_conf_read(tc, ofs); reg |= TX39_UARTCTRL1_ENUART; reg &= ~TX39_UARTCTRL1_ENBREAHALT; - tx_conf_write(tc, TX39_UARTCTRL1_REG(slot), reg); + tx_conf_write(tc, ofs, reg); + + timeout = 100; + + while(!(tx_conf_read(tc, ofs) & TX39_UARTCTRL1_UARTON) && + --timeout > 0) + ; + + if (timeout == 0) { + printf("UART%c never power up\n", "AB"[chip->sc_slot]); + return 1; + } + /* * XXX Disable DMA (DMA not coded yet) */ reg &= ~(TX39_UARTCTRL1_ENDMARX | TX39_UARTCTRL1_ENDMATX); - tx_conf_write(tc, TX39_UARTCTRL1_REG(slot), reg); + tx_conf_write(tc, ofs, reg); - /* XXX Clock */ + /* Supply clock XXX should call clock module routine. */ reg = tx_conf_read(tc, TX39_CLOCKCTRL_REG); reg |= (slot ? TX39_CLOCK_ENUARTBCLK : TX39_CLOCK_ENUARTACLK); tx_conf_write(tc, TX39_CLOCKCTRL_REG, reg); - return 0; } void -txcom_disable(sc) - struct txcom_softc *sc; +txcom_disable(chip) + struct txcom_chip *chip; { tx_chipset_tag_t tc; txreg_t reg; int slot; - tc = sc->sc_tc; - slot = sc->sc_slot; + tc = chip->sc_tc; + slot = chip->sc_slot; reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot)); /* DMA */ reg &= ~(TX39_UARTCTRL1_ENDMARX | TX39_UARTCTRL1_ENDMATX); + /* Power */ reg &= ~TX39_UARTCTRL1_ENUART; tx_conf_write(tc, TX39_UARTCTRL1_REG(slot), reg); + /* Clock */ reg = tx_conf_read(tc, TX39_CLOCKCTRL_REG); reg &= ~(slot ? TX39_CLOCK_ENUARTBCLK : TX39_CLOCK_ENUARTACLK); @@ -256,27 +293,25 @@ txcom_disable(sc) } -int -txcom_cnattach(slot, speed, cflag) - int slot, speed, cflag; +__inline int +__txcom_txbufready(chip, retry) + struct txcom_chip *chip; + int retry; { - cn_tab = &txcomcons; + tx_chipset_tag_t tc = chip->sc_tc; + int ofs = TX39_UARTCTRL1_REG(chip->sc_slot); - cn_sc.sc_tc = tx_conf_get_tag(); - cn_sc.sc_slot = slot; - cn_sc.sc_cflag = cflag; - cn_sc.sc_speed = speed; - cn_sc.sc_hwflags |= TXCOM_HW_CONSOLE; -#ifdef WINCE_DEFAULT_SETTING -#warning WINCE_DEFAULT_SETTING -#else - txcom_enable(&cn_sc); - txcom_setmode(&cn_sc); - txcom_setbaudrate(&cn_sc); -#endif + do { + if (tx_conf_read(tc, ofs) & TX39_UARTCTRL1_EMPTY) + return 1; + } while(--retry != 0); + return 0; } +/* + * console + */ int txcom_cngetc(dev) dev_t dev; @@ -284,20 +319,19 @@ txcom_cngetc(dev) tx_chipset_tag_t tc; int ofs, c, s; - s = splhigh(); + s = spltty(); - tc = cn_sc.sc_tc; - ofs = TX39_UARTCTRL1_REG(cn_sc.sc_slot); + tc = txcom_chip.sc_tc; + ofs = TX39_UARTCTRL1_REG(txcom_chip.sc_slot); while(!(TX39_UARTCTRL1_RXHOLDFULL & tx_conf_read(tc, ofs))) ; - ofs = TX39_UARTRXHOLD_REG(cn_sc.sc_slot); - c = TX39_UARTRXHOLD_RXDATA(tx_conf_read(tc, ofs)); + c = TX39_UARTRXHOLD_RXDATA( + tx_conf_read(tc, TX39_UARTRXHOLD_REG(txcom_chip.sc_slot))); - if (c == '\r') { + if (c == '\r') c = '\n'; - } splx(s); @@ -309,25 +343,21 @@ txcom_cnputc(dev, c) dev_t dev; int c; { - tx_chipset_tag_t tc; - int ofs, s; + struct txcom_chip *chip = &txcom_chip; + tx_chipset_tag_t tc = chip->sc_tc; + int s; - s = splhigh(); + s = spltty(); - tc = cn_sc.sc_tc; - ofs = TX39_UARTCTRL1_REG(cn_sc.sc_slot); + /* Wait for transmitter to empty */ + __txcom_txbufready(chip, -1); - while (!(tx_conf_read(tc, ofs) & TX39_UARTCTRL1_EMPTY)) - ; - - tx_conf_write(tc, TX39_UARTTXHOLD_REG(cn_sc.sc_slot), + tx_conf_write(tc, TX39_UARTTXHOLD_REG(chip->sc_slot), (c & TX39_UARTTXHOLD_TXDATA_MASK)); - while (!(tx_conf_read(tc, ofs) & TX39_UARTCTRL1_EMPTY)) - ; - + __txcom_txbufready(chip, -1); + splx(s); - } void @@ -338,14 +368,14 @@ txcom_cnpollc(dev, on) } void -txcom_setmode(sc) - struct txcom_softc *sc; +txcom_setmode(chip) + struct txcom_chip *chip; { - tcflag_t cflag; + tcflag_t cflag = chip->sc_cflag; + int ofs = TX39_UARTCTRL1_REG(chip->sc_slot); txreg_t reg; - cflag = sc->sc_cflag; - reg = tx_conf_read(sc->sc_tc, TX39_UARTCTRL1_REG(sc->sc_slot)); + reg = tx_conf_read(chip->sc_tc, ofs); switch (ISSET(cflag, CSIZE)) { default: @@ -358,6 +388,7 @@ txcom_setmode(sc) reg &= ~TX39_UARTCTRL1_BIT7; break; } + if (ISSET(cflag, PARENB)) { reg |= TX39_UARTCTRL1_ENPARITY; if (ISSET(cflag, PARODD)) { @@ -368,40 +399,121 @@ txcom_setmode(sc) } else { reg &= ~TX39_UARTCTRL1_ENPARITY; } + if (ISSET(cflag, CSTOPB)) { reg |= TX39_UARTCTRL1_TWOSTOP; } - tx_conf_write(sc->sc_tc, TX39_UARTCTRL1_REG(sc->sc_slot), reg); - + + tx_conf_write(chip->sc_tc, ofs, reg); } void -txcom_setbaudrate(sc) - struct txcom_softc *sc; +txcom_setbaudrate(chip) + struct txcom_chip *chip; { int baudrate; txreg_t reg; - baudrate = TX39_UARTCLOCKHZ / (sc->sc_speed * 16) - 1; + if (chip->sc_speed == 0) + return; + + baudrate = TX39_UARTCLOCKHZ / (chip->sc_speed * 16) - 1; reg = TX39_UARTCTRL2_BAUDRATE_SET(0, baudrate); - tx_conf_write(sc->sc_tc, TX39_UARTCTRL2_REG(sc->sc_slot), reg); + tx_conf_write(chip->sc_tc, TX39_UARTCTRL2_REG(chip->sc_slot), reg); +} + +int +txcom_cnattach(slot, speed, cflag) + int slot, speed, cflag; +{ + cn_tab = &txcomcons; + + txcom_chip.sc_tc = tx_conf_get_tag(); + txcom_chip.sc_slot = slot; + txcom_chip.sc_cflag = cflag; + txcom_chip.sc_speed = speed; + txcom_chip.sc_hwflags |= TXCOM_HW_CONSOLE; + + txcom_enable(&txcom_chip); + txcom_setmode(&txcom_chip); + txcom_setbaudrate(&txcom_chip); + + return 0; +} + +/* + * tty + */ +void +txcom_break(sc, on) + struct txcom_softc *sc; + int on; +{ + struct txcom_chip *chip = sc->sc_chip; + + tx_conf_write(chip->sc_tc, TX39_UARTTXHOLD_REG(chip->sc_slot), + on ? TX39_UARTTXHOLD_BREAK : 0); } void -txcom_rxsoft(arg) - void *arg; +txcom_modem(sc, on) + struct txcom_softc *sc; + int on; +{ + struct txcom_chip *chip = sc->sc_chip; + tx_chipset_tag_t tc = chip->sc_tc; + int slot = chip->sc_slot; + txreg_t reg; + + reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot)); + + if (on) { + reg &= ~TX39_UARTCTRL1_DISTXD; + } else { + reg |= TX39_UARTCTRL1_DISTXD; + } + + reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot)); +} + +void +txcom_shutdown(sc) + struct txcom_softc *sc; { - struct txcom_softc *sc = arg; struct tty *tp = sc->sc_tty; - int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint; - int code = sc->sc_rbuf; + int s = spltty(); - DPRINTF(("txcom_rxsoft %c %08x\n", code, code)); - com_softrxintr_scheduled = 0; + /* Clear any break condition set with TIOCSBRK. */ + txcom_break(sc, 0); - if ((*rint)(code, tp) == -1) { + /* + * Hang up if necessary. Wait a bit, so the other side has time to + * notice even if we immediately open the port again. + */ + if (ISSET(tp->t_cflag, HUPCL)) { + txcom_modem(sc, 0); + (void) tsleep(sc, TTIPRI, ttclos, hz); + } + + /* Turn off interrupts if not the console. */ + if (!ISSET(sc->sc_chip->sc_hwflags, TXCOM_HW_CONSOLE)) { + txcom_disable(sc->sc_chip); + } + + splx(s); +} + +__inline const char * +__txcom_slotname(slot) + int slot; +{ + static const char *slotname[] = {"UARTA", "UARTB"}; + if (slot != 0 && slot != 1) { + return "bogus slot"; + } else { + return slotname[slot]; } } @@ -411,47 +523,135 @@ txcom_overrun_intr(arg) { struct txcom_softc *sc = arg; - printf("UART%c overrun\n", sc->sc_slot ? 'B' : 'A'); + printf("%s overrun\n", __txcom_slotname(sc->sc_chip->sc_slot)); return 0; } int -txcom_a_rxintr(arg) +txcom_frameerr_intr(arg) void *arg; { struct txcom_softc *sc = arg; - u_int8_t c; - - if (!com_softrxintr_scheduled) { - com_softrxintr_scheduled = 1; - timeout(txcom_rxsoft, arg, 1); - } - DPRINTF(("txcom_rxintr\n")); - c = 0xff & tx_conf_read(sc->sc_tc, TX39_UARTRXHOLD_REG(sc->sc_slot)); - sc->sc_rbuf = c; + + printf("%s frame error\n", __txcom_slotname(sc->sc_chip->sc_slot)); return 0; } int -txcom_b_rxintr(arg) +txcom_parityerr_intr(arg) void *arg; { struct txcom_softc *sc = arg; - u_int8_t c; - - if (!com_softrxintr_scheduled) { - com_softrxintr_scheduled = 1; - timeout(txcom_rxsoft, arg, 1); - } - DPRINTF(("txcom_rxintr\n")); - c = 0xff & tx_conf_read(sc->sc_tc, TX39_UARTRXHOLD_REG(sc->sc_slot)); - sc->sc_rbuf = c; + + printf("%s parity error\n", __txcom_slotname(sc->sc_chip->sc_slot)); return 0; } +int +txcom_break_intr(arg) + void *arg; +{ + struct txcom_softc *sc = arg; + + printf("%s break\n", __txcom_slotname(sc->sc_chip->sc_slot)); + + return 0; +} + +int +txcom_rxintr(arg) + void *arg; +{ + struct txcom_softc *sc = arg; + struct txcom_chip *chip = sc->sc_chip; + u_int8_t c; + + c = TX39_UARTRXHOLD_RXDATA( + tx_conf_read(chip->sc_tc, + TX39_UARTRXHOLD_REG(chip->sc_slot))); + + sc->sc_rbuf[sc->sc_rbput] = c; + sc->sc_rbput = (sc->sc_rbput + 1) % TXCOM_RING_MASK; + + timeout(txcom_rxsoft, arg, 1); + + return 0; +} + +void +txcom_rxsoft(arg) + void *arg; +{ + struct txcom_softc *sc = arg; + struct tty *tp = sc->sc_tty; + int (*rint) __P((int c, struct tty *tp)); + int code; + int s, end, get; + + rint = linesw[tp->t_line].l_rint; + + s = spltty(); + end = sc->sc_rbput; + get = sc->sc_rbget; + + while (get != end) { + code = sc->sc_rbuf[get]; + + if ((*rint)(code, tp) == -1) { + /* + * The line discipline's buffer is out of space. + */ + } + get = (get + 1) % TXCOM_RING_MASK; + } + sc->sc_rbget = get; + + splx(s); +} + +int +txcom_txintr(arg) + void *arg; +{ + struct txcom_softc *sc = arg; + struct txcom_chip *chip = sc->sc_chip; + tx_chipset_tag_t tc = chip->sc_tc; + + if (sc->sc_tbc > 0) { + tx_conf_write(tc, TX39_UARTTXHOLD_REG(chip->sc_slot), + (*sc->sc_tba & + TX39_UARTTXHOLD_TXDATA_MASK)); + sc->sc_tbc--; + sc->sc_tba++; + } else { + timeout(txcom_txsoft, arg, 1); + } + + return 0; +} + +void +txcom_txsoft(arg) + void *arg; +{ + struct txcom_softc *sc = arg; + struct tty *tp = sc->sc_tty; + int s = spltty(); + + CLR(tp->t_state, TS_BUSY); + if (ISSET(tp->t_state, TS_FLUSH)) { + CLR(tp->t_state, TS_FLUSH); + } else { + ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); + } + + (*linesw[tp->t_line].l_start)(tp); + + splx(s); +} int txcomopen(dev, flag, mode, p) @@ -460,35 +660,91 @@ txcomopen(dev, flag, mode, p) struct proc *p; { struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)]; - struct tty *tp = sc->sc_tty; - int err; + struct txcom_chip *chip; + struct tty *tp; + int s, err; struct termios t; - tp->t_dev = dev; + if (!sc) + return ENXIO; - /* XXX XXX XXX */ + chip = sc->sc_chip; + tp = sc->sc_tty; + + if (ISSET(tp->t_state, TS_ISOPEN) && + ISSET(tp->t_state, TS_XCLUDE) && + p->p_ucred->cr_uid != 0) + return (EBUSY); + + s = spltty(); + + tp->t_dev = dev; tp->t_ispeed = 0; - tp->t_ospeed = 9600; - tp->t_cflag = (TTYDEF_CFLAG & ~(CSIZE | PARENB)) | CS8 | CLOCAL | HUPCL; - txcomparam(tp, &t); /* not yet */ - /* XXX XXX XXX */ + tp->t_ospeed = 0; + + t.c_ispeed = 0; + if (ISSET(chip->sc_hwflags, TXCOM_HW_CONSOLE)) { + t.c_ospeed = chip->sc_speed; + t.c_cflag = chip->sc_cflag; + } else { + t.c_ospeed = TTYDEF_SPEED; + t.c_cflag = TTYDEF_CFLAG; + } + + if (ISSET(chip->sc_swflags, TIOCFLAG_CLOCAL)) + SET(t.c_cflag, CLOCAL); + if (ISSET(chip->sc_swflags, TIOCFLAG_CRTSCTS)) + SET(t.c_cflag, CRTSCTS); + if (ISSET(chip->sc_swflags, TIOCFLAG_MDMBUF)) + SET(t.c_cflag, MDMBUF); + + txcom_enable(sc->sc_chip); + + txcomparam(tp, &t); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; + ttychars(tp); ttsetwater(tp); + /* + * Turn on DTR. We must always do this, even if carrier is not + * present, because otherwise we'd have to use TIOCSDTR + * immediately after setting CLOCAL, which applications do not + * expect. We always assert DTR while the device is open + * unless explicitly requested to deassert it. + */ + txcom_modem(sc, 1); + + /* Clear the input ring, and unblock. */ + sc->sc_rbget = sc->sc_rbput = 0; + + splx(s); + if ((err = ttyopen(tp, minor(dev), ISSET(flag, O_NONBLOCK)))) { DPRINTF(("txcomopen: ttyopen failed\n")); - return err; + goto out; } if ((err = (*linesw[tp->t_line].l_open)(dev, tp))) { DPRINTF(("txcomopen: line dicipline open failed\n")); - return err; + goto out; } return err; + + out: + if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { + /* + * We failed to open the device, and nobody else had it opened. + * Clean up the state as appropriate. + */ + txcom_shutdown(sc); + } + + return err; + } int @@ -500,10 +756,22 @@ txcomclose(dev, flag, mode, p) struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)]; struct tty *tp = sc->sc_tty; - DPRINTF(("txcomclose\n")); + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return 0; + (*linesw[tp->t_line].l_close)(tp, flag); ttyclose(tp); + if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { + /* + * Although we got a last close, the device may still be in + * use; e.g. if this was the dialout node, and there are still + * processes waiting for carrier on the non-dialout node. + */ + txcom_shutdown(sc); + } + return 0; } @@ -515,7 +783,7 @@ txcomread(dev, uio, flag) { struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)]; struct tty *tp = sc->sc_tty; - DPRINTF(("txcomread\n")); + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); } @@ -528,7 +796,6 @@ txcomwrite(dev, uio, flag) struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)]; struct tty *tp = sc->sc_tty; - DPRINTF(("txcomwrite\n")); return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } @@ -537,9 +804,8 @@ txcomtty(dev) dev_t dev; { struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)]; - struct tty *tp = sc->sc_tty; - DPRINTF(("txcomtty\n")); - return tp; + + return sc->sc_tty; } int @@ -552,18 +818,56 @@ txcomioctl(dev, cmd, data, flag, p) { struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)]; struct tty *tp = sc->sc_tty; - int error; + int s, err; - DPRINTF(("txcomioctl\n")); - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); - if (error >= 0) - return (error); + err = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (err >= 0) { + return err; + } - error = ttioctl(tp, cmd, data, flag, p); - if (error >= 0) - return (error); + err = ttioctl(tp, cmd, data, flag, p); + if (err >= 0) { + return err; + } - return 0; + err = 0; + + s = spltty(); + + switch (cmd) { + case TIOCSBRK: + txcom_break(sc, 1); + break; + + case TIOCCBRK: + txcom_break(sc, 0); + break; + + case TIOCSDTR: + txcom_modem(sc, 1); + break; + + case TIOCCDTR: + txcom_modem(sc, 0); + break; + + case TIOCGFLAGS: + *(int *)data = sc->sc_chip->sc_swflags; + break; + + case TIOCSFLAGS: + err = suser(p->p_ucred, &p->p_acflag); + if (err) { + break; + } + sc->sc_chip->sc_swflags = *(int *)data; + break; + + } + + splx(s); + + return err; } void @@ -574,7 +878,6 @@ txcomstop(tp, flag) struct txcom_softc *sc = txcom_cd.cd_devs[minor(tp->t_dev)]; int s; - DPRINTF(("txcomstop\n")); s = spltty(); if (ISSET(tp->t_state, TS_BUSY)) { @@ -584,6 +887,7 @@ txcomstop(tp, flag) if (!ISSET(tp->t_state, TS_TTSTOP)) SET(tp->t_state, TS_FLUSH); } + splx(s); } @@ -592,12 +896,16 @@ txcomstart(tp) struct tty *tp; { struct txcom_softc *sc = txcom_cd.cd_devs[minor(tp->t_dev)]; + struct txcom_chip *chip = sc->sc_chip; + tx_chipset_tag_t tc = chip->sc_tc; + int slot = chip->sc_slot; int s; - DPRINTF(("txcomstart\n")); s = spltty(); - if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) - return; + + if (!__txcom_txbufready(chip, 0) || + ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) + goto out; if (tp->t_outq.c_cc <= tp->t_lowat) { if (ISSET(tp->t_state, TS_ASLEEP)) { @@ -606,29 +914,95 @@ txcomstart(tp) } selwakeup(&tp->t_wsel); if (tp->t_outq.c_cc == 0) - return; + goto out; } + sc->sc_tba = tp->t_outq.c_cf; sc->sc_tbc = ndqb(&tp->t_outq, 0); - while (sc->sc_tbc-- > 0) { - txcom_cnputc(tp->t_dev, *sc->sc_tba++); - } - sc->sc_tbc = 0; + SET(tp->t_state, TS_BUSY); - CLR(tp->t_state, TS_BUSY); - if (ISSET(tp->t_state, TS_FLUSH)) { - CLR(tp->t_state, TS_FLUSH); - } else { - ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); - } + /* Output the first character of the contiguous buffer. */ + tx_conf_write(tc, TX39_UARTTXHOLD_REG(slot), + (*sc->sc_tba & TX39_UARTTXHOLD_TXDATA_MASK)); + + sc->sc_tbc--; + sc->sc_tba++; + + out: splx(s); } +/* + * Set TXcom tty parameters from termios. + */ int txcomparam(tp, t) struct tty *tp; struct termios *t; { - DPRINTF(("txcomparam\n")); + struct txcom_softc *sc = txcom_cd.cd_devs[minor(tp->t_dev)]; + struct txcom_chip *chip; + int ospeed, cflag; + int s; + + if (!sc) + return ENXIO; + + ospeed = t->c_ospeed; + cflag = t->c_cflag; + + /* Check requested parameters. */ + if (ospeed < 0) { + return EINVAL; + } + if (t->c_ispeed && t->c_ispeed != ospeed) { + return EINVAL; + } + + s = spltty(); + chip = sc->sc_chip; + /* + * For the console, always force CLOCAL and !HUPCL, so that the port + * is always active. + */ + if (ISSET(chip->sc_swflags, TIOCFLAG_SOFTCAR) || + ISSET(chip->sc_hwflags, TXCOM_HW_CONSOLE)) { + SET(cflag, CLOCAL); + CLR(cflag, HUPCL); + } + splx(s); + + /* + * Only whack the UART when params change. + * Some callers need to clear tp->t_ospeed + * to make sure initialization gets done. + */ + if (tp->t_ospeed == ospeed && tp->t_cflag == cflag) { + return 0; + } + + s = spltty(); + chip = sc->sc_chip; + chip->sc_speed = ospeed; + chip->sc_cflag = cflag; + + txcom_setmode(chip); + txcom_setbaudrate(chip); + + /* And copy to tty. */ + tp->t_ispeed = 0; + tp->t_ospeed = chip->sc_speed; + tp->t_cflag = chip->sc_cflag; + + /* + * If hardware flow control is disabled, unblock any hard flow + * control state. + */ + if (!ISSET(chip->sc_cflag, CHWFLOW)) { + txcomstart(tp); + } + + splx(s); + return 0; }