Home | History | Annotate | Line # | Download | only in tx
txcom.c revision 1.8
      1 /*	$NetBSD: txcom.c,v 1.8 2000/03/23 06:38:03 thorpej Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1999, 2000, by UCHIYAMA Yasushi
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. The name of the developer may NOT be used to endorse or promote products
     13  *    derived from this software without specific prior written permission.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  *
     27  */
     28 #include "opt_tx39_debug.h"
     29 #include "opt_tx39uartdebug.h"
     30 
     31 #include <sys/param.h>
     32 #include <sys/systm.h>
     33 #include <sys/kernel.h>
     34 #include <sys/device.h>
     35 #include <sys/malloc.h>
     36 
     37 #include <sys/proc.h> /* tsleep/wakeup */
     38 
     39 #include <sys/ioctl.h>
     40 #include <sys/select.h>
     41 #include <sys/file.h>
     42 
     43 #include <sys/tty.h>
     44 #include <sys/conf.h>
     45 #include <dev/cons.h> /* consdev */
     46 
     47 #include <machine/bus.h>
     48 
     49 #include <hpcmips/tx/tx39var.h>
     50 #include <hpcmips/tx/tx39icureg.h>
     51 #include <hpcmips/tx/tx39uartvar.h>
     52 #include <hpcmips/tx/tx39uartreg.h>
     53 
     54 #include <hpcmips/tx/tx39irvar.h>
     55 
     56 #include <hpcmips/tx/tx39clockreg.h> /* XXX */
     57 
     58 #include <hpcmips/tx/txiomanvar.h>
     59 
     60 #define SET(t, f)	(t) |= (f)
     61 #define CLR(t, f)	(t) &= ~(f)
     62 #define ISSET(t, f)	((t) & (f))
     63 
     64 #ifdef TX39UARTDEBUG
     65 #define	DPRINTF(arg) printf arg
     66 #else
     67 #define	DPRINTF(arg)
     68 #endif
     69 
     70 #define TXCOM_HW_CONSOLE	0x40
     71 #define	TXCOM_RING_SIZE		256 /* must be a power of two! */
     72 #define TXCOM_RING_MASK		(TXCOM_RING_SIZE - 1)
     73 
     74 struct txcom_chip {
     75 	tx_chipset_tag_t sc_tc;
     76 	int sc_slot;	/* UARTA or UARTB */
     77 	int sc_cflag;
     78 	int sc_speed;
     79 	int sc_swflags;
     80 	int sc_hwflags;
     81 
     82 	int sc_dcd;
     83 };
     84 
     85 struct txcom_softc {
     86 	struct	device		sc_dev;
     87 	struct tty		*sc_tty;
     88 	struct txcom_chip	*sc_chip;
     89 
     90 	struct callout		sc_txsoft_ch;
     91 	struct callout		sc_rxsoft_ch;
     92 
     93  	u_int8_t	*sc_tba;	/* transmit buffer address */
     94  	int		sc_tbc;		/* transmit byte count */
     95 	int		sc_heldtbc;
     96 	u_int8_t	*sc_rbuf;	/* receive buffer address */
     97 	int		sc_rbput;	/* receive byte count */
     98 	int		sc_rbget;
     99 };
    100 
    101 extern struct cfdriver txcom_cd;
    102 
    103 int	txcom_match	__P((struct device*, struct cfdata*, void*));
    104 void	txcom_attach	__P((struct device*, struct device*, void*));
    105 int	txcom_print	__P((void*, const char*));
    106 
    107 int	txcom_txintr		__P((void*));
    108 int	txcom_rxintr		__P((void*));
    109 int	txcom_frameerr_intr	__P((void*));
    110 int	txcom_parityerr_intr	__P((void*));
    111 int	txcom_break_intr	__P((void*));
    112 
    113 void	txcom_rxsoft	__P((void*));
    114 void	txcom_txsoft	__P((void*));
    115 
    116 int	txcom_stsoft	__P((void*));
    117 int	txcom_stsoft2	__P((void*));
    118 int	txcom_stsoft3	__P((void*));
    119 int	txcom_stsoft4	__P((void*));
    120 
    121 
    122 void	txcom_shutdown	__P((struct txcom_softc*));
    123 void	txcom_break	__P((struct txcom_softc*, int));
    124 void	txcom_modem	__P((struct txcom_softc*, int));
    125 void	txcomstart	__P((struct tty*));
    126 int	txcomparam	__P((struct tty*, struct termios*));
    127 
    128 void	txcom_reset		__P((struct txcom_chip*));
    129 int	txcom_enable		__P((struct txcom_chip*));
    130 void	txcom_disable		__P((struct txcom_chip*));
    131 void	txcom_setmode		__P((struct txcom_chip*));
    132 void	txcom_setbaudrate	__P((struct txcom_chip*));
    133 int	txcom_cngetc		__P((dev_t));
    134 void	txcom_cnputc		__P((dev_t, int));
    135 void	txcom_cnpollc		__P((dev_t, int));
    136 
    137 __inline int	__txcom_txbufready __P((struct txcom_chip*, int));
    138 __inline const char *__txcom_slotname __P((int));
    139 
    140 void	txcom_dump	__P((struct txcom_chip*));
    141 
    142 cdev_decl(txcom);
    143 
    144 struct consdev txcomcons = {
    145 	NULL, NULL, txcom_cngetc, txcom_cnputc, txcom_cnpollc,
    146 	    NULL, NODEV, CN_NORMAL
    147 };
    148 
    149 /* Serial console */
    150 struct txcom_chip txcom_chip;
    151 
    152 struct cfattach txcom_ca = {
    153 	sizeof(struct txcom_softc), txcom_match, txcom_attach
    154 };
    155 
    156 int
    157 txcom_match(parent, cf, aux)
    158 	struct device *parent;
    159 	struct cfdata *cf;
    160 	void *aux;
    161 {
    162 	/* if the autoconfiguration got this far, there's a slot here */
    163 	return 1;
    164 }
    165 
    166 void
    167 txcom_attach(parent, self, aux)
    168 	struct device *parent;
    169 	struct device *self;
    170 	void *aux;
    171 {
    172 	struct tx39uart_attach_args *ua = aux;
    173 	struct txcom_softc *sc = (void*)self;
    174 	tx_chipset_tag_t tc;
    175 	struct tty *tp;
    176 	struct txcom_chip *chip;
    177 	int slot, console;
    178 
    179 	/* Check this slot used as serial console */
    180 	console = (ua->ua_slot == txcom_chip.sc_slot) &&
    181 		(txcom_chip.sc_hwflags & TXCOM_HW_CONSOLE);
    182 
    183 	if (console) {
    184 		sc->sc_chip = &txcom_chip;
    185 	} else {
    186 		if (!(sc->sc_chip = malloc(sizeof(struct txcom_chip),
    187 					   M_DEVBUF, M_WAITOK))) {
    188 			printf(": can't allocate chip\n");
    189 			return;
    190 		}
    191 		memset(sc->sc_chip, 0, sizeof(struct txcom_chip));
    192 	}
    193 
    194 	chip = sc->sc_chip;
    195 	tc = chip->sc_tc = ua->ua_tc;
    196 	slot = chip->sc_slot = ua->ua_slot;
    197 
    198 #ifdef TX39UARTDEBUG
    199 	txcom_dump(chip);
    200 #endif
    201 	if (!console)
    202 		txcom_reset(chip);
    203 
    204 	if (!(sc->sc_rbuf = malloc(TXCOM_RING_SIZE, M_DEVBUF, M_WAITOK))) {
    205 		printf(": can't allocate buffer.\n");
    206 		return;
    207 	}
    208 	memset(sc->sc_rbuf, 0, TXCOM_RING_SIZE);
    209 
    210 	tp = ttymalloc();
    211 	tp->t_oproc = txcomstart;
    212 	tp->t_param = txcomparam;
    213 	tp->t_hwiflow = NULL;
    214 	sc->sc_tty = tp;
    215 	tty_attach(tp);
    216 
    217 	if (ISSET(chip->sc_hwflags, TXCOM_HW_CONSOLE)) {
    218 		int maj;
    219 		/* locate the major number */
    220 		for (maj = 0; maj < nchrdev; maj++)
    221 			if (cdevsw[maj].d_open == txcomopen)
    222 				break;
    223 
    224 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
    225 
    226 		printf(": console");
    227 	}
    228 
    229 	printf("\n");
    230 
    231 	/*
    232 	 * Enable interrupt
    233 	 */
    234 #define TXCOMINTR(i, s) MAKEINTR(2, TX39_INTRSTATUS2_UART##i##INT(s))
    235 
    236 	tx_intr_establish(tc, TXCOMINTR(RX, slot), IST_EDGE, IPL_TTY,
    237 			  txcom_rxintr, sc);
    238 	tx_intr_establish(tc, TXCOMINTR(TX, slot), IST_EDGE, IPL_TTY,
    239 			  txcom_txintr, sc);
    240 	tx_intr_establish(tc, TXCOMINTR(RXOVERRUN, slot), IST_EDGE, IPL_TTY,
    241 			  txcom_rxintr, sc);
    242 	tx_intr_establish(tc, TXCOMINTR(TXOVERRUN, slot), IST_EDGE, IPL_TTY,
    243 			  txcom_txintr, sc);
    244 	tx_intr_establish(tc, TXCOMINTR(FRAMEERR, slot), IST_EDGE, IPL_TTY,
    245 			  txcom_frameerr_intr, sc);
    246 	tx_intr_establish(tc, TXCOMINTR(PARITYERR, slot), IST_EDGE, IPL_TTY,
    247 			  txcom_parityerr_intr, sc);
    248 	tx_intr_establish(tc, TXCOMINTR(BREAK, slot), IST_EDGE, IPL_TTY,
    249 			  txcom_break_intr, sc);
    250 
    251 	if (ua->ua_slot == 0)
    252 		txioman_uarta_init(tc, self);
    253 
    254 	/*
    255 	 * UARTB can connect IR module
    256 	 */
    257 	if (ua->ua_slot == 1) {
    258 		struct txcom_attach_args tca;
    259 		tca.tca_tc = tc;
    260 		tca.tca_parent = self;
    261 		config_found(self, &tca, txcom_print);
    262 	}
    263 }
    264 
    265 int
    266 txcom_print(aux, pnp)
    267 	void *aux;
    268 	const char *pnp;
    269 {
    270 	return pnp ? QUIET : UNCONF;
    271 }
    272 
    273 void
    274 txcom_reset(chip)
    275 	struct txcom_chip *chip;
    276 {
    277 	tx_chipset_tag_t tc;
    278 	int slot, ofs;
    279 	txreg_t reg;
    280 
    281 	tc = chip->sc_tc;
    282 	slot = chip->sc_slot;
    283 	ofs = TX39_UARTCTRL1_REG(slot);
    284 
    285 	/* Supply clock */
    286 	reg = tx_conf_read(tc, TX39_CLOCKCTRL_REG);
    287 	reg |= (slot ? TX39_CLOCK_ENUARTBCLK : TX39_CLOCK_ENUARTACLK);
    288 	tx_conf_write(tc, TX39_CLOCKCTRL_REG, reg);
    289 
    290 	/* reset UART module */
    291 	tx_conf_write(tc, ofs, 0);
    292 }
    293 
    294 int
    295 txcom_enable(chip)
    296 	struct txcom_chip *chip;
    297 {
    298 	tx_chipset_tag_t tc;
    299 	txreg_t reg;
    300 	int slot, ofs, timeout;
    301 
    302 	tc = chip->sc_tc;
    303 	slot = chip->sc_slot;
    304 	ofs = TX39_UARTCTRL1_REG(slot);
    305 
    306 	/* Supply clock */
    307 	reg = tx_conf_read(tc, TX39_CLOCKCTRL_REG);
    308 	reg |= (slot ? TX39_CLOCK_ENUARTBCLK : TX39_CLOCK_ENUARTACLK);
    309 	tx_conf_write(tc, TX39_CLOCKCTRL_REG, reg);
    310 
    311 	/*
    312 	 * XXX Disable DMA (DMA not coded yet)
    313 	 */
    314 	reg = tx_conf_read(tc, ofs);
    315 	reg &= ~(TX39_UARTCTRL1_ENDMARX | TX39_UARTCTRL1_ENDMATX);
    316 	tx_conf_write(tc, ofs, reg);
    317 
    318 	/* enable */
    319 	reg = tx_conf_read(tc, ofs);
    320 	reg |= TX39_UARTCTRL1_ENUART;
    321 	reg &= ~TX39_UARTCTRL1_ENBREAHALT;
    322 	tx_conf_write(tc, ofs, reg);
    323 
    324 	timeout = 100;
    325 
    326 	while(!(tx_conf_read(tc, ofs) & TX39_UARTCTRL1_UARTON) &&
    327 	      --timeout > 0)
    328 		;
    329 
    330 	if (timeout == 0 && !cold) {
    331 		printf("%s never power up\n", __txcom_slotname(slot));
    332 		return 1;
    333 	}
    334 
    335 	return 0;
    336 }
    337 
    338 void
    339 txcom_disable(chip)
    340 	struct txcom_chip *chip;
    341 {
    342 	tx_chipset_tag_t tc;
    343 	txreg_t reg;
    344 	int slot;
    345 
    346 	tc = chip->sc_tc;
    347 	slot = chip->sc_slot;
    348 
    349 	reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot));
    350 	/* DMA */
    351 	reg &= ~(TX39_UARTCTRL1_ENDMARX | TX39_UARTCTRL1_ENDMATX);
    352 
    353 	/* disable module */
    354 	reg &= ~TX39_UARTCTRL1_ENUART;
    355 	tx_conf_write(tc, TX39_UARTCTRL1_REG(slot), reg);
    356 
    357 	/* Clock */
    358 	reg = tx_conf_read(tc, TX39_CLOCKCTRL_REG);
    359 	reg &= ~(slot ? TX39_CLOCK_ENUARTBCLK : TX39_CLOCK_ENUARTACLK);
    360 	tx_conf_write(tc, TX39_CLOCKCTRL_REG, reg);
    361 
    362 }
    363 
    364 __inline int
    365 __txcom_txbufready(chip, retry)
    366 	struct txcom_chip *chip;
    367 	int retry;
    368 {
    369 	tx_chipset_tag_t tc = chip->sc_tc;
    370 	int ofs = TX39_UARTCTRL1_REG(chip->sc_slot);
    371 
    372 	do {
    373 		if (tx_conf_read(tc, ofs) & TX39_UARTCTRL1_EMPTY)
    374 			return 1;
    375 	} while(--retry != 0);
    376 
    377 	return 0;
    378 }
    379 
    380 void
    381 txcom_pulse_mode(dev)
    382 	struct device *dev;
    383 {
    384 	struct txcom_softc *sc = (void*)dev;
    385 	struct txcom_chip *chip = sc->sc_chip;
    386 	tx_chipset_tag_t tc = chip->sc_tc;
    387 	int ofs;
    388 	txreg_t reg;
    389 
    390 	ofs = TX39_UARTCTRL1_REG(chip->sc_slot);
    391 
    392 	reg = tx_conf_read(tc, ofs);
    393 	/* WindowsCE use this setting */
    394 	reg |= TX39_UARTCTRL1_PULSEOPT1;
    395 	reg &= ~TX39_UARTCTRL1_PULSEOPT2;
    396 	reg |= TX39_UARTCTRL1_DTINVERT;
    397 
    398 	tx_conf_write(tc, ofs, reg);
    399 }
    400 
    401 /*
    402  * console
    403  */
    404 int
    405 txcom_cngetc(dev)
    406 	dev_t dev;
    407 {
    408 	tx_chipset_tag_t tc;
    409 	int ofs, c, s;
    410 
    411 	s = spltty();
    412 
    413 	tc = txcom_chip.sc_tc;
    414 	ofs = TX39_UARTCTRL1_REG(txcom_chip.sc_slot);
    415 
    416 	while(!(TX39_UARTCTRL1_RXHOLDFULL & tx_conf_read(tc, ofs)))
    417 		;
    418 
    419 	c = TX39_UARTRXHOLD_RXDATA(
    420 		tx_conf_read(tc, TX39_UARTRXHOLD_REG(txcom_chip.sc_slot)));
    421 
    422 	if (c == '\r')
    423 		c = '\n';
    424 
    425 	splx(s);
    426 
    427 	return c;
    428 }
    429 
    430 void
    431 txcom_cnputc(dev, c)
    432 	dev_t dev;
    433 	int c;
    434 {
    435 	struct txcom_chip *chip = &txcom_chip;
    436 	tx_chipset_tag_t tc = chip->sc_tc;
    437 	int s;
    438 
    439 	s = spltty();
    440 
    441 	/* Wait for transmitter to empty */
    442 	__txcom_txbufready(chip, -1);
    443 
    444 	tx_conf_write(tc, TX39_UARTTXHOLD_REG(chip->sc_slot),
    445 		      (c & TX39_UARTTXHOLD_TXDATA_MASK));
    446 
    447 	__txcom_txbufready(chip, -1);
    448 
    449 	splx(s);
    450 }
    451 
    452 void
    453 txcom_cnpollc(dev, on)
    454 	dev_t dev;
    455 	int on;
    456 {
    457 }
    458 
    459 void
    460 txcom_setmode(chip)
    461 	struct txcom_chip *chip;
    462 {
    463 	tcflag_t cflag = chip->sc_cflag;
    464 	int ofs = TX39_UARTCTRL1_REG(chip->sc_slot);
    465 	txreg_t reg;
    466 
    467 	reg = tx_conf_read(chip->sc_tc, ofs);
    468 	reg &= ~TX39_UARTCTRL1_ENUART;
    469 	tx_conf_write(chip->sc_tc, ofs, reg);
    470 
    471 	switch (ISSET(cflag, CSIZE)) {
    472 	default:
    473 		printf("txcom_setmode: CS7, CS8 only. use CS7");
    474 		/* FALL THROUGH */
    475 	case CS7:
    476 		reg |= TX39_UARTCTRL1_BIT7;
    477 		break;
    478 	case CS8:
    479 		reg &= ~TX39_UARTCTRL1_BIT7;
    480 		break;
    481 	}
    482 
    483 	if (ISSET(cflag, PARENB)) {
    484 		reg |= TX39_UARTCTRL1_ENPARITY;
    485 		if (ISSET(cflag, PARODD)) {
    486 			reg &= ~TX39_UARTCTRL1_EVENPARITY;
    487 		} else {
    488 			reg |= TX39_UARTCTRL1_EVENPARITY;
    489 		}
    490 	} else {
    491 		reg &= ~TX39_UARTCTRL1_ENPARITY;
    492 	}
    493 
    494 	if (ISSET(cflag, CSTOPB))
    495 		reg |= TX39_UARTCTRL1_TWOSTOP;
    496 	else
    497 		reg &= ~TX39_UARTCTRL1_TWOSTOP;
    498 
    499 	reg |= TX39_UARTCTRL1_ENUART;
    500 	tx_conf_write(chip->sc_tc, ofs, reg);
    501 }
    502 
    503 void
    504 txcom_setbaudrate(chip)
    505 	struct txcom_chip *chip;
    506 {
    507 	int baudrate;
    508 	int ofs = TX39_UARTCTRL1_REG(chip->sc_slot);
    509 	txreg_t reg, reg1;
    510 
    511 	if (chip->sc_speed == 0)
    512 		return;
    513 
    514 	if (!cold)
    515 		DPRINTF(("txcom_setbaudrate: %d\n", chip->sc_speed));
    516 
    517 	reg1 = tx_conf_read(chip->sc_tc, ofs);
    518 	reg1 &= ~TX39_UARTCTRL1_ENUART;
    519 	tx_conf_write(chip->sc_tc, ofs, reg1);
    520 
    521 	baudrate = TX39_UARTCLOCKHZ / (chip->sc_speed * 16) - 1;
    522 	reg = TX39_UARTCTRL2_BAUDRATE_SET(0, baudrate);
    523 
    524 	tx_conf_write(chip->sc_tc, TX39_UARTCTRL2_REG(chip->sc_slot), reg);
    525 
    526 	reg1 |= TX39_UARTCTRL1_ENUART;
    527 	tx_conf_write(chip->sc_tc, ofs, reg1);
    528 }
    529 
    530 int
    531 txcom_cnattach(slot, speed, cflag)
    532 	int slot, speed, cflag;
    533 {
    534 	cn_tab = &txcomcons;
    535 
    536 	txcom_chip.sc_tc	= tx_conf_get_tag();
    537 	txcom_chip.sc_slot	= slot;
    538 	txcom_chip.sc_cflag	= cflag;
    539 	txcom_chip.sc_speed	= speed;
    540 	txcom_chip.sc_hwflags |= TXCOM_HW_CONSOLE;
    541 #if notyet
    542 	txcom_reset(&txcom_chip);
    543 #endif
    544 	txcom_setmode(&txcom_chip);
    545 	txcom_setbaudrate(&txcom_chip);
    546 
    547 	if (txcom_enable(&txcom_chip))
    548 		return 1;
    549 
    550 	return 0;
    551 }
    552 
    553 /*
    554  * tty
    555  */
    556 void
    557 txcom_break(sc, on)
    558 	struct txcom_softc *sc;
    559 	int on;
    560 {
    561 	struct txcom_chip *chip = sc->sc_chip;
    562 
    563 	tx_conf_write(chip->sc_tc, TX39_UARTTXHOLD_REG(chip->sc_slot),
    564 		      on ? TX39_UARTTXHOLD_BREAK : 0);
    565 }
    566 
    567 void
    568 txcom_modem(sc, on)
    569 	struct txcom_softc *sc;
    570 	int on;
    571 {
    572 	struct txcom_chip *chip = sc->sc_chip;
    573 	tx_chipset_tag_t tc = chip->sc_tc;
    574 	int slot = chip->sc_slot;
    575 	txreg_t reg;
    576 
    577 	reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot));
    578 	reg &= ~TX39_UARTCTRL1_ENUART;
    579 	tx_conf_write(tc, TX39_UARTCTRL1_REG(slot), reg);
    580 
    581 	if (on) {
    582 		reg &= ~TX39_UARTCTRL1_DISTXD;
    583 	} else {
    584 		reg |= TX39_UARTCTRL1_DISTXD; /* low UARTTXD */
    585 	}
    586 
    587 	reg |= TX39_UARTCTRL1_ENUART;
    588 	tx_conf_write(tc, TX39_UARTCTRL1_REG(slot), reg);
    589 }
    590 
    591 void
    592 txcom_shutdown(sc)
    593 	struct txcom_softc *sc;
    594 {
    595 	struct tty *tp = sc->sc_tty;
    596 	int s = spltty();
    597 
    598 	/* Clear any break condition set with TIOCSBRK. */
    599 	txcom_break(sc, 0);
    600 
    601 	/*
    602 	 * Hang up if necessary.  Wait a bit, so the other side has time to
    603 	 * notice even if we immediately open the port again.
    604 	 */
    605 	if (ISSET(tp->t_cflag, HUPCL)) {
    606 		txcom_modem(sc, 0);
    607 		(void) tsleep(sc, TTIPRI, ttclos, hz);
    608 	}
    609 
    610 
    611 	/* Turn off interrupts if not the console. */
    612 	if (!ISSET(sc->sc_chip->sc_hwflags, TXCOM_HW_CONSOLE)) {
    613 		txcom_disable(sc->sc_chip);
    614 	}
    615 
    616 	splx(s);
    617 }
    618 
    619 __inline const char *
    620 __txcom_slotname(slot)
    621 	int slot;
    622 {
    623 	static const char *slotname[] = {"UARTA", "UARTB"};
    624 	if (slot != 0 && slot != 1) {
    625 		return "bogus slot";
    626 	} else {
    627 		return slotname[slot];
    628 	}
    629 }
    630 
    631 int
    632 txcom_frameerr_intr(arg)
    633 	void *arg;
    634 {
    635 	struct txcom_softc *sc = arg;
    636 
    637 	printf("%s frame error\n", __txcom_slotname(sc->sc_chip->sc_slot));
    638 
    639 	return 0;
    640 }
    641 
    642 int
    643 txcom_parityerr_intr(arg)
    644 	void *arg;
    645 {
    646 	struct txcom_softc *sc = arg;
    647 
    648 	printf("%s parity error\n", __txcom_slotname(sc->sc_chip->sc_slot));
    649 
    650 	return 0;
    651 }
    652 
    653 int
    654 txcom_break_intr(arg)
    655 	void *arg;
    656 {
    657 	struct txcom_softc *sc = arg;
    658 
    659 	printf("%s break\n", __txcom_slotname(sc->sc_chip->sc_slot));
    660 
    661 	return 0;
    662 }
    663 
    664 int
    665 txcom_rxintr(arg)
    666 	void *arg;
    667 {
    668 	struct txcom_softc *sc = arg;
    669 	struct txcom_chip *chip = sc->sc_chip;
    670 	u_int8_t c;
    671 
    672 	c = TX39_UARTRXHOLD_RXDATA(
    673 		tx_conf_read(chip->sc_tc,
    674 			     TX39_UARTRXHOLD_REG(chip->sc_slot)));
    675 
    676 	sc->sc_rbuf[sc->sc_rbput] = c;
    677 	sc->sc_rbput = (sc->sc_rbput + 1) % TXCOM_RING_MASK;
    678 
    679 	callout_reset(&sc->sc_rxsoft_ch, 1, txcom_rxsoft, sc);
    680 
    681 	return 0;
    682 }
    683 
    684 void
    685 txcom_rxsoft(arg)
    686 	void *arg;
    687 {
    688 	struct txcom_softc *sc = arg;
    689 	struct tty *tp = sc->sc_tty;
    690 	int (*rint) __P((int c, struct tty *tp));
    691 	int code;
    692 	int s, end, get;
    693 
    694 	rint = linesw[tp->t_line].l_rint;
    695 
    696 	s = spltty();
    697 	end = sc->sc_rbput;
    698 	get = sc->sc_rbget;
    699 
    700 	while (get != end) {
    701 		code = sc->sc_rbuf[get];
    702 
    703 		if ((*rint)(code, tp) == -1) {
    704 			/*
    705 			 * The line discipline's buffer is out of space.
    706 			 */
    707 		}
    708 		get = (get + 1) % TXCOM_RING_MASK;
    709 	}
    710 	sc->sc_rbget = get;
    711 
    712 	splx(s);
    713 }
    714 
    715 int
    716 txcom_txintr(arg)
    717 	void *arg;
    718 {
    719 	struct txcom_softc *sc = arg;
    720 	struct txcom_chip *chip = sc->sc_chip;
    721 	tx_chipset_tag_t tc = chip->sc_tc;
    722 
    723 	if (sc->sc_tbc > 0) {
    724 		tx_conf_write(tc, TX39_UARTTXHOLD_REG(chip->sc_slot),
    725 			      (*sc->sc_tba &
    726 			       TX39_UARTTXHOLD_TXDATA_MASK));
    727 		sc->sc_tbc--;
    728 		sc->sc_tba++;
    729 	} else {
    730 		callout_reset(&sc->sc_rxsoft_ch, 1, txcom_txsoft, sc);
    731 	}
    732 
    733 	return 0;
    734 }
    735 
    736 void
    737 txcom_txsoft(arg)
    738 	void *arg;
    739 {
    740 	struct txcom_softc *sc = arg;
    741 	struct tty *tp = sc->sc_tty;
    742 	int s = spltty();
    743 
    744 	CLR(tp->t_state, TS_BUSY);
    745 	if (ISSET(tp->t_state, TS_FLUSH)) {
    746 		CLR(tp->t_state, TS_FLUSH);
    747 	} else {
    748 		ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
    749 	}
    750 
    751 	(*linesw[tp->t_line].l_start)(tp);
    752 
    753 	splx(s);
    754 }
    755 
    756 int
    757 txcomopen(dev, flag, mode, p)
    758 	dev_t dev;
    759 	int flag, mode;
    760 	struct proc *p;
    761 {
    762 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)];
    763 	struct txcom_chip *chip;
    764 	struct tty *tp;
    765 	int s, err;
    766 
    767 	if (!sc)
    768 		return ENXIO;
    769 
    770 	chip = sc->sc_chip;
    771 	tp = sc->sc_tty;
    772 
    773 	if (ISSET(tp->t_state, TS_ISOPEN) &&
    774 	    ISSET(tp->t_state, TS_XCLUDE) &&
    775 	    p->p_ucred->cr_uid != 0)
    776 		return (EBUSY);
    777 
    778 	s = spltty();
    779 
    780 	if (txcom_enable(sc->sc_chip)) {
    781 		splx(s);
    782 		goto out;
    783 	}
    784 	/*
    785 	 * Do the following iff this is a first open.
    786 	 */
    787 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    788 		struct termios t;
    789 
    790 		tp->t_dev = dev;
    791 
    792 		t.c_ispeed = 0;
    793 		if (ISSET(chip->sc_hwflags, TXCOM_HW_CONSOLE)) {
    794 			t.c_ospeed = chip->sc_speed;
    795 			t.c_cflag = chip->sc_cflag;
    796 		} else {
    797 			t.c_ospeed = TTYDEF_SPEED;
    798 			t.c_cflag = TTYDEF_CFLAG;
    799 		}
    800 
    801 		if (ISSET(chip->sc_swflags, TIOCFLAG_CLOCAL))
    802 			SET(t.c_cflag, CLOCAL);
    803 		if (ISSET(chip->sc_swflags, TIOCFLAG_CRTSCTS))
    804 			SET(t.c_cflag, CRTSCTS);
    805 		if (ISSET(chip->sc_swflags, TIOCFLAG_MDMBUF))
    806 			SET(t.c_cflag, MDMBUF);
    807 
    808 		/* Make sure txcomparam() will do something. */
    809 		tp->t_ospeed = 0;
    810 		txcomparam(tp, &t);
    811 
    812 		tp->t_iflag = TTYDEF_IFLAG;
    813 		tp->t_oflag = TTYDEF_OFLAG;
    814 		tp->t_lflag = TTYDEF_LFLAG;
    815 
    816 		ttychars(tp);
    817 		ttsetwater(tp);
    818 
    819 		/*
    820 		 * Turn on DTR.  We must always do this, even if carrier is not
    821 		 * present, because otherwise we'd have to use TIOCSDTR
    822 		 * immediately after setting CLOCAL, which applications do not
    823 		 * expect.  We always assert DTR while the device is open
    824 		 * unless explicitly requested to deassert it.
    825 		 */
    826 		txcom_modem(sc, 1);
    827 
    828 		/* Clear the input ring, and unblock. */
    829 		sc->sc_rbget = sc->sc_rbput = 0;
    830 	}
    831 
    832 	splx(s);
    833 #define	TXCOMDIALOUT(x)	(minor(x) & 0x80000)
    834 	if ((err = ttyopen(tp, TXCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK)))) {
    835 		DPRINTF(("txcomopen: ttyopen failed\n"));
    836 		goto out;
    837 	}
    838 	if ((err = (*linesw[tp->t_line].l_open)(dev, tp))) {
    839 		DPRINTF(("txcomopen: line dicipline open failed\n"));
    840 		goto out;
    841 	}
    842 
    843 	return err;
    844 
    845  out:
    846 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    847 		/*
    848 		 * We failed to open the device, and nobody else had it opened.
    849 		 * Clean up the state as appropriate.
    850 		 */
    851 		txcom_shutdown(sc);
    852 	}
    853 
    854 	return err;
    855 
    856 }
    857 
    858 int
    859 txcomclose(dev, flag, mode, p)
    860 	dev_t dev;
    861 	int flag, mode;
    862 	struct proc *p;
    863 {
    864 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)];
    865 	struct tty *tp = sc->sc_tty;
    866 
    867 	/* XXX This is for cons.c. */
    868 	if (!ISSET(tp->t_state, TS_ISOPEN))
    869 		return 0;
    870 
    871 	(*linesw[tp->t_line].l_close)(tp, flag);
    872 	ttyclose(tp);
    873 
    874 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    875 		/*
    876 		 * Although we got a last close, the device may still be in
    877 		 * use; e.g. if this was the dialout node, and there are still
    878 		 * processes waiting for carrier on the non-dialout node.
    879 		 */
    880 		txcom_shutdown(sc);
    881 	}
    882 
    883 	return 0;
    884 }
    885 
    886 int
    887 txcomread(dev, uio, flag)
    888 	dev_t dev;
    889 	struct uio *uio;
    890 	int flag;
    891 {
    892 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)];
    893 	struct tty *tp = sc->sc_tty;
    894 
    895 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
    896 }
    897 
    898 int
    899 txcomwrite(dev, uio, flag)
    900 	dev_t dev;
    901 	struct uio *uio;
    902 	int flag;
    903 {
    904 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)];
    905 	struct tty *tp = sc->sc_tty;
    906 
    907 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    908 }
    909 
    910 struct tty *
    911 txcomtty(dev)
    912 	dev_t dev;
    913 {
    914 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)];
    915 
    916 	return sc->sc_tty;
    917 }
    918 
    919 int
    920 txcomioctl(dev, cmd, data, flag, p)
    921 	dev_t dev;
    922 	u_long cmd;
    923 	caddr_t data;
    924 	int flag;
    925 	struct proc *p;
    926 {
    927 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(dev)];
    928 	struct tty *tp = sc->sc_tty;
    929 	int s, err;
    930 
    931 	err = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    932 	if (err >= 0) {
    933 		return err;
    934 	}
    935 
    936 	err = ttioctl(tp, cmd, data, flag, p);
    937 	if (err >= 0) {
    938 		return err;
    939 	}
    940 
    941 	err = 0;
    942 
    943 	s = spltty();
    944 
    945 	switch (cmd) {
    946 	default:
    947 		err = ENOTTY;
    948 		break;
    949 
    950 	case TIOCSBRK:
    951 		txcom_break(sc, 1);
    952 		break;
    953 
    954 	case TIOCCBRK:
    955 		txcom_break(sc, 0);
    956 		break;
    957 
    958 	case TIOCSDTR:
    959 		txcom_modem(sc, 1);
    960 		break;
    961 
    962 	case TIOCCDTR:
    963 		txcom_modem(sc, 0);
    964 		break;
    965 
    966 	case TIOCGFLAGS:
    967 		*(int *)data = sc->sc_chip->sc_swflags;
    968 		break;
    969 
    970 	case TIOCSFLAGS:
    971 		err = suser(p->p_ucred, &p->p_acflag);
    972 		if (err) {
    973 			break;
    974 		}
    975 		sc->sc_chip->sc_swflags = *(int *)data;
    976 		break;
    977 
    978 	}
    979 
    980 	splx(s);
    981 
    982 	return err;
    983 }
    984 
    985 void
    986 txcomstop(tp, flag)
    987 	struct tty *tp;
    988 	int flag;
    989 {
    990 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(tp->t_dev)];
    991 	int s;
    992 
    993 	s = spltty();
    994 
    995 	if (ISSET(tp->t_state, TS_BUSY)) {
    996 		/* Stop transmitting at the next chunk. */
    997 		sc->sc_tbc = 0;
    998 		sc->sc_heldtbc = 0;
    999 		if (!ISSET(tp->t_state, TS_TTSTOP))
   1000 			SET(tp->t_state, TS_FLUSH);
   1001 	}
   1002 
   1003 	splx(s);
   1004 }
   1005 
   1006 void
   1007 txcomstart(tp)
   1008 	struct tty *tp;
   1009 {
   1010 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(tp->t_dev)];
   1011 	struct txcom_chip *chip = sc->sc_chip;
   1012 	tx_chipset_tag_t tc = chip->sc_tc;
   1013 	int slot = chip->sc_slot;
   1014 	int s;
   1015 
   1016 	s = spltty();
   1017 
   1018 	if (!__txcom_txbufready(chip, 0) ||
   1019 	    ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
   1020 		goto out;
   1021 
   1022 	if (tp->t_outq.c_cc <= tp->t_lowat) {
   1023 		if (ISSET(tp->t_state, TS_ASLEEP)) {
   1024 			CLR(tp->t_state, TS_ASLEEP);
   1025 			wakeup(&tp->t_outq);
   1026 		}
   1027 		selwakeup(&tp->t_wsel);
   1028 		if (tp->t_outq.c_cc == 0)
   1029 			goto out;
   1030 	}
   1031 
   1032 	sc->sc_tba = tp->t_outq.c_cf;
   1033 	sc->sc_tbc = ndqb(&tp->t_outq, 0);
   1034 	SET(tp->t_state, TS_BUSY);
   1035 
   1036 	/* Output the first character of the contiguous buffer. */
   1037 	tx_conf_write(tc, TX39_UARTTXHOLD_REG(slot),
   1038 		      (*sc->sc_tba & TX39_UARTTXHOLD_TXDATA_MASK));
   1039 
   1040 	sc->sc_tbc--;
   1041 	sc->sc_tba++;
   1042 
   1043  out:
   1044 	splx(s);
   1045 }
   1046 
   1047 /*
   1048  * Set TXcom tty parameters from termios.
   1049  */
   1050 int
   1051 txcomparam(tp, t)
   1052 	struct tty *tp;
   1053 	struct termios *t;
   1054 {
   1055 	struct txcom_softc *sc = txcom_cd.cd_devs[minor(tp->t_dev)];
   1056 	struct txcom_chip *chip;
   1057 	int ospeed;
   1058 	int s;
   1059 
   1060 	if (!sc)
   1061 		return ENXIO;
   1062 
   1063 	ospeed = t->c_ospeed;
   1064 
   1065 	/* Check requested parameters. */
   1066 	if (ospeed < 0) {
   1067 		return EINVAL;
   1068 	}
   1069 	if (t->c_ispeed && t->c_ispeed != ospeed) {
   1070 		return EINVAL;
   1071 	}
   1072 
   1073 	s = spltty();
   1074 	chip = sc->sc_chip;
   1075 	/*
   1076 	 * For the console, always force CLOCAL and !HUPCL, so that the port
   1077 	 * is always active.
   1078 	 */
   1079 	if (ISSET(chip->sc_swflags, TIOCFLAG_SOFTCAR) ||
   1080 	    ISSET(chip->sc_hwflags, TXCOM_HW_CONSOLE)) {
   1081 		SET(t->c_cflag, CLOCAL);
   1082 		CLR(t->c_cflag, HUPCL);
   1083 	}
   1084 	splx(s);
   1085 
   1086 	/*
   1087 	 * If we're not in a mode that assumes a connection is present, then
   1088 	 * ignore carrier changes.
   1089 	 */
   1090 	if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
   1091 		chip->sc_dcd = 0;
   1092 	else
   1093 		chip->sc_dcd = 1;
   1094 
   1095 	/*
   1096 	 * Only whack the UART when params change.
   1097 	 * Some callers need to clear tp->t_ospeed
   1098 	 * to make sure initialization gets done.
   1099 	 */
   1100 	if (tp->t_ospeed == ospeed && tp->t_cflag == t->c_cflag) {
   1101 		return 0;
   1102 	}
   1103 
   1104 	s = spltty();
   1105 	chip = sc->sc_chip;
   1106 	chip->sc_speed = ospeed;
   1107 	chip->sc_cflag = t->c_cflag;
   1108 
   1109 	txcom_setmode(chip);
   1110 	txcom_setbaudrate(chip);
   1111 
   1112 	/* And copy to tty. */
   1113 	tp->t_ispeed = 0;
   1114 	tp->t_ospeed = chip->sc_speed;
   1115 	tp->t_cflag = chip->sc_cflag;
   1116 
   1117 	/*
   1118 	 * Update the tty layer's idea of the carrier bit, in case we changed
   1119 	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
   1120 	 * explicit request.
   1121 	 */
   1122 	(void) (*linesw[tp->t_line].l_modem)(tp, chip->sc_dcd);
   1123 
   1124 	/*
   1125 	 * If hardware flow control is disabled, unblock any hard flow
   1126 	 * control state.
   1127 	 */
   1128 	if (!ISSET(chip->sc_cflag, CHWFLOW)) {
   1129 		txcomstart(tp);
   1130 	}
   1131 
   1132 	splx(s);
   1133 
   1134 	return 0;
   1135 }
   1136 
   1137 void
   1138 txcom_dump(chip)
   1139 	struct txcom_chip *chip;
   1140 {
   1141 	tx_chipset_tag_t tc = chip->sc_tc;
   1142 	int slot = chip->sc_slot;
   1143 	txreg_t reg;
   1144 
   1145 	reg = tx_conf_read(tc, TX39_UARTCTRL1_REG(slot));
   1146 #define ISSETPRINT(r, m) \
   1147 	__is_set_print(r, TX39_UARTCTRL1_##m, #m)
   1148 	ISSETPRINT(reg, UARTON);
   1149 	ISSETPRINT(reg, EMPTY);
   1150 	ISSETPRINT(reg, PRXHOLDFULL);
   1151 	ISSETPRINT(reg, RXHOLDFULL);
   1152 	ISSETPRINT(reg, ENDMARX);
   1153 	ISSETPRINT(reg, ENDMATX);
   1154 	ISSETPRINT(reg, TESTMODE);
   1155 	ISSETPRINT(reg, ENBREAHALT);
   1156 	ISSETPRINT(reg, ENDMATEST);
   1157 	ISSETPRINT(reg, ENDMALOOP);
   1158 	ISSETPRINT(reg, PULSEOPT2);
   1159 	ISSETPRINT(reg, PULSEOPT1);
   1160 	ISSETPRINT(reg, DTINVERT);
   1161 	ISSETPRINT(reg, DISTXD);
   1162 	ISSETPRINT(reg, TWOSTOP);
   1163 	ISSETPRINT(reg, LOOPBACK);
   1164 	ISSETPRINT(reg, BIT7);
   1165 	ISSETPRINT(reg, EVENPARITY);
   1166 	ISSETPRINT(reg, ENPARITY);
   1167 	ISSETPRINT(reg, ENUART);
   1168 }
   1169 
   1170 /*
   1171  * Compaq-C function.
   1172  */
   1173 #include <hpcmips/tx/tx39iovar.h>
   1174 
   1175 int	__compaq_uart_dcd	__P((void*));
   1176 int	__mobilon_uart_dcd	__P((void*));
   1177 
   1178 int
   1179 __compaq_uart_dcd(arg)
   1180 	void *arg;
   1181 {
   1182 	struct txcom_softc *sc = arg;
   1183 	struct tty *tp = sc->sc_tty;
   1184 	struct txcom_chip *chip = sc->sc_chip;
   1185 	int modem;
   1186 
   1187 	switch (tx39intrvec) {
   1188 	default:
   1189 		return 0;
   1190 	case ((3 << 16) | 30): /* MFIO 30 positive edge */
   1191 		tx39io_portout(chip->sc_tc, TXPORT(TXMFIO, 31), TXON);
   1192 		modem = 1;
   1193 		break;
   1194 	case ((4 << 16) | 30): /* MFIO 30 negative edge */
   1195 		tx39io_portout(chip->sc_tc, TXPORT(TXMFIO, 31), TXOFF);
   1196 		modem = 1;
   1197 		break;
   1198 	case ((3 << 16) | 5): /* MFIO 5 positive edge */
   1199 		tx39io_portout(chip->sc_tc, TXPORT(TXMFIO, 6), TXON);
   1200 		modem = 0;
   1201 		break;
   1202 	case ((4 << 16) | 5): /* MFIO 5 negative edge */
   1203 		tx39io_portout(chip->sc_tc, TXPORT(TXMFIO, 6), TXOFF);
   1204 		modem = 0;
   1205 		break;
   1206 	}
   1207 
   1208 	if (modem && chip->sc_dcd)
   1209 		(void) (*linesw[tp->t_line].l_modem)(tp, chip->sc_dcd);
   1210 
   1211 	return 0;
   1212 }
   1213 
   1214 int
   1215 __mobilon_uart_dcd(arg)
   1216 	void *arg;
   1217 {
   1218 	struct txcom_softc *sc = arg;
   1219 	struct tty *tp = sc->sc_tty;
   1220 	struct txcom_chip *chip = sc->sc_chip;
   1221 	int modem;
   1222 
   1223 	switch (tx39intrvec) {
   1224 	default:
   1225 		return 0;
   1226 	case ((5 << 16) | 4): /* IO 4 positive edge */
   1227 		modem = 1;
   1228 		break;
   1229 	case ((5 << 16) | 11): /* IO 4 negative edge */
   1230 		modem = 1;
   1231 		break;
   1232 	case ((5 << 16) | 6): /* IO 6 positive edge */
   1233 		modem = 0;
   1234 		break;
   1235 	case ((5 << 16) | 13): /* IO 6 negative edge */
   1236 		modem = 0;
   1237 		break;
   1238 	}
   1239 
   1240 	if (modem && chip->sc_dcd)
   1241 		(void) (*linesw[tp->t_line].l_modem)(tp, chip->sc_dcd);
   1242 
   1243 	return 0;
   1244 }
   1245