Home | History | Annotate | Line # | Download | only in dev
dcm.c revision 1.20
      1 /*	$NetBSD: dcm.c,v 1.20 1995/12/02 18:18:50 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Jason R. Thorpe.  All rights reserved.
      5  * Copyright (c) 1988 University of Utah.
      6  * Copyright (c) 1982, 1986, 1990, 1993
      7  *	The Regents of the University of California.  All rights reserved.
      8  *
      9  * This code is derived from software contributed to Berkeley by
     10  * the Systems Programming Group of the University of Utah Computer
     11  * Science Department.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. All advertising materials mentioning features or use of this software
     22  *    must display the following acknowledgement:
     23  *	This product includes software developed by the University of
     24  *	California, Berkeley and its contributors.
     25  * 4. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  * from Utah: $Hdr: dcm.c 1.29 92/01/21$
     42  *
     43  *	@(#)dcm.c	8.4 (Berkeley) 1/12/94
     44  */
     45 
     46 /*
     47  * TODO:
     48  *	Timeouts
     49  *	Test console support.
     50  */
     51 
     52 #include "dcm.h"
     53 #if NDCM > 0
     54 /*
     55  *  98642/MUX
     56  */
     57 #include <sys/param.h>
     58 #include <sys/systm.h>
     59 #include <sys/ioctl.h>
     60 #include <sys/proc.h>
     61 #include <sys/tty.h>
     62 #include <sys/conf.h>
     63 #include <sys/file.h>
     64 #include <sys/uio.h>
     65 #include <sys/kernel.h>
     66 #include <sys/syslog.h>
     67 #include <sys/time.h>
     68 
     69 #include <machine/cpu.h>
     70 
     71 #include <hp300/dev/device.h>
     72 #include <hp300/dev/dcmreg.h>
     73 #include <hp300/hp300/isr.h>
     74 
     75 #ifndef DEFAULT_BAUD_RATE
     76 #define DEFAULT_BAUD_RATE 9600
     77 #endif
     78 
     79 int	dcmmatch(), dcmintr(), dcmparam();
     80 void	dcmattach(), dcmstart();
     81 struct	driver dcmdriver = {
     82 	dcmmatch, dcmattach, "dcm",
     83 };
     84 
     85 struct speedtab dcmspeedtab[] = {
     86 	0,	BR_0,
     87 	50,	BR_50,
     88 	75,	BR_75,
     89 	110,	BR_110,
     90 	134,	BR_134,
     91 	150,	BR_150,
     92 	300,	BR_300,
     93 	600,	BR_600,
     94 	1200,	BR_1200,
     95 	1800,	BR_1800,
     96 	2400,	BR_2400,
     97 	4800,	BR_4800,
     98 	9600,	BR_9600,
     99 	19200,	BR_19200,
    100 	38400,	BR_38400,
    101 	-1,	-1
    102 };
    103 
    104 /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
    105 #define	DCM_USPERCH(s)	(10000000 / (s))
    106 
    107 /*
    108  * Per board interrupt scheme.  16.7ms is the polling interrupt rate
    109  * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
    110  */
    111 #define DIS_TIMER	0
    112 #define DIS_PERCHAR	1
    113 #define DIS_RESET	2
    114 
    115 int	dcmistype = -1;		/* -1 == dynamic, 0 == timer, 1 == perchar */
    116 int     dcminterval = 5;	/* interval (secs) between checks */
    117 struct	dcmischeme {
    118 	int	dis_perchar;	/* non-zero if interrupting per char */
    119 	long	dis_time;	/* last time examined */
    120 	int	dis_intr;	/* recv interrupts during last interval */
    121 	int	dis_char;	/* characters read during last interval */
    122 };
    123 
    124 /*
    125  * Console support
    126  */
    127 #ifdef DCMCONSOLE
    128 int	dcmconsole = DCMCONSOLE;
    129 #else
    130 int	dcmconsole = -1;
    131 #endif
    132 int	dcmconsinit;
    133 int	dcmdefaultrate = DEFAULT_BAUD_RATE;
    134 int	dcmconbrdbusy = 0;
    135 int	dcmmajor;
    136 
    137 #ifdef KGDB
    138 /*
    139  * Kernel GDB support
    140  */
    141 #include <machine/remote-sl.h>
    142 
    143 extern dev_t kgdb_dev;
    144 extern int kgdb_rate;
    145 extern int kgdb_debug_init;
    146 #endif
    147 
    148 /* #define DCMSTATS */
    149 
    150 #ifdef DEBUG
    151 int	dcmdebug = 0x0;
    152 #define DDB_SIOERR	0x01
    153 #define DDB_PARAM	0x02
    154 #define DDB_INPUT	0x04
    155 #define DDB_OUTPUT	0x08
    156 #define DDB_INTR	0x10
    157 #define DDB_IOCTL	0x20
    158 #define DDB_INTSCHM	0x40
    159 #define DDB_MODEM	0x80
    160 #define DDB_OPENCLOSE	0x100
    161 #endif
    162 
    163 #ifdef DCMSTATS
    164 #define	DCMRBSIZE	94
    165 #define DCMXBSIZE	24
    166 
    167 struct	dcmstats {
    168 	long	xints;		    /* # of xmit ints */
    169 	long	xchars;		    /* # of xmit chars */
    170 	long	xempty;		    /* times outq is empty in dcmstart */
    171 	long	xrestarts;	    /* times completed while xmitting */
    172 	long	rints;		    /* # of recv ints */
    173 	long	rchars;		    /* # of recv chars */
    174 	long	xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
    175 	long	rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
    176 };
    177 #endif
    178 
    179 #define DCMUNIT(x)		minor(x)
    180 #define	DCMBOARD(x)		(((x) >> 2) & 0x3f)
    181 #define DCMPORT(x)		((x) & 3)
    182 
    183 /*
    184  * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
    185  * the distribution panel uses "HP DCE" conventions.  If requested via
    186  * the device flags, we swap the inputs to something closer to normal DCE,
    187  * allowing a straight-through cable to a DTE or a reversed cable
    188  * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
    189  * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
    190  * DSR or make RTS work, though).  The following gives the full
    191  * details of a cable from this mux panel to a modem:
    192  *
    193  *		     HP		    modem
    194  *		name	pin	pin	name
    195  * HP inputs:
    196  *		"Rx"	 2	 3	Tx
    197  *		CTS	 4	 5	CTS	(only needed for CCTS_OFLOW)
    198  *		DCD	20	 8	DCD
    199  *		"DSR"	 9	 6	DSR	(unneeded)
    200  *		RI	22	22	RI	(unneeded)
    201  *
    202  * HP outputs:
    203  *		"Tx"	 3	 2	Rx
    204  *		"DTR"	 6	not connected
    205  *		"RTS"	 8	20	DTR
    206  *		"SR"	23	 4	RTS	(often not needed)
    207  */
    208 #define hp2dce_in(ibits)	(iconv[(ibits) & 0xf])
    209 static char iconv[16] = {
    210 	0,		MI_DM,		MI_CTS,		MI_CTS|MI_DM,
    211 	MI_CD,		MI_CD|MI_DM,	MI_CD|MI_CTS,	MI_CD|MI_CTS|MI_DM,
    212 	MI_RI,		MI_RI|MI_DM,	MI_RI|MI_CTS,	MI_RI|MI_CTS|MI_DM,
    213 	MI_RI|MI_CD,	MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
    214 	MI_RI|MI_CD|MI_CTS|MI_DM
    215 };
    216 
    217 #define	NDCMPORT	4	/* XXX what about 8-port cards? */
    218 
    219 struct	dcm_softc {
    220 	struct	hp_device *sc_hd;	/* device info */
    221 	struct	dcmdevice *sc_dcm;	/* pointer to hardware */
    222 	struct	tty *sc_tty[NDCMPORT];	/* our tty instances */
    223 	struct	modemreg *sc_modem[NDCMPORT]; /* modem control */
    224 	char	sc_mcndlast[NDCMPORT];	/* XXX last modem status for port */
    225 	struct	isr sc_isr;		/* interrupt handler */
    226 	short	sc_softCAR;		/* mask of ports with soft-carrier */
    227 	struct	dcmischeme sc_scheme;	/* interrupt scheme for board */
    228 
    229 	/*
    230 	 * Mask of soft-carrier bits in config flags.
    231 	 * XXX What about 8-port cards?
    232 	 */
    233 #define	DCM_SOFTCAR	0x0000000f
    234 
    235 	int	sc_flags;		/* misc. configuration info */
    236 
    237 	/*
    238 	 * Bits for sc_flags
    239 	 */
    240 #define	DCM_ACTIVE	0x00000001	/* indicates board is alive */
    241 #define	DCM_STDDCE	0x00000010	/* re-map DCE to standard */
    242 #define	DCM_FLAGMASK	(DCM_STDDCE)	/* mask of valid bits in config flags */
    243 
    244 #ifdef DCMSTATS
    245 	struct	dcmstats sc_stats;	/* metrics gathering */
    246 #endif
    247 } dcm_softc[NDCM];
    248 
    249 int
    250 dcmmatch(hd)
    251 	register struct hp_device *hd;
    252 {
    253 	struct dcm_softc *sc = &dcm_softc[hd->hp_unit];
    254 	struct dcmdevice *dcm;
    255 	int i, timo = 0;
    256 	int s, brd, isconsole, mbits;
    257 
    258 	dcm = (struct dcmdevice *)hd->hp_addr;
    259 	if ((dcm->dcm_rsid & 0x1f) != DCMID)
    260 		return (0);
    261 
    262 	brd = hd->hp_unit;
    263 	isconsole = (brd == DCMBOARD(dcmconsole));
    264 
    265 	/*
    266 	 * XXX selected console device (CONSUNIT) as determined by
    267 	 * dcmcnprobe does not agree with logical numbering imposed
    268 	 * by the config file (i.e. lowest address DCM is not unit
    269 	 * CONSUNIT).  Don't recognize this card.
    270 	 */
    271 	if (isconsole && (dcm != sc->sc_dcm))
    272 		return (0);
    273 
    274 	sc->sc_hd = hd;
    275 	hd->hp_ipl = DCMIPL(dcm->dcm_ic);
    276 
    277 	/*
    278 	 * Empirically derived self-test magic
    279 	 */
    280 	s = spltty();
    281 	dcm->dcm_rsid = DCMRS;
    282 	DELAY(50000);	/* 5000 is not long enough */
    283 	dcm->dcm_rsid = 0;
    284 	dcm->dcm_ic = IC_IE;
    285 	dcm->dcm_cr = CR_SELFT;
    286 	while ((dcm->dcm_ic & IC_IR) == 0)
    287 		if (++timo == 20000)
    288 			return (0);
    289 	DELAY(50000)	/* XXX why is this needed ???? */
    290 	while ((dcm->dcm_iir & IIR_SELFT) == 0)
    291 		if (++timo == 400000)
    292 			return (0);
    293 	DELAY(50000)	/* XXX why is this needed ???? */
    294 	if (dcm->dcm_stcon != ST_OK) {
    295 		if (!isconsole)
    296 			printf("dcm%d: self test failed: %x\n",
    297 			       brd, dcm->dcm_stcon);
    298 		return (0);
    299 	}
    300 	dcm->dcm_ic = IC_ID;
    301 	splx(s);
    302 
    303 	return (1);
    304 }
    305 
    306 void
    307 dcmattach(hd)
    308 	register struct hp_device *hd;
    309 {
    310 	struct dcm_softc *sc = &dcm_softc[hd->hp_unit];
    311 	struct dcmdevice *dcm;
    312 	int i, timo = 0;
    313 	int s, brd, isconsole, mbits;
    314 
    315 	dcm = sc->sc_dcm = (struct dcmdevice *)hd->hp_addr;
    316 
    317 	brd = hd->hp_unit;
    318 	isconsole = (brd == DCMBOARD(dcmconsole));
    319 
    320 	/* Extract configuration info from flags. */
    321 	sc->sc_softCAR = (hd->hp_flags & DCM_SOFTCAR);
    322 	sc->sc_flags = (hd->hp_flags & DCM_FLAGMASK);
    323 
    324 	/* Mark our unit as configured. */
    325 	sc->sc_flags |= DCM_ACTIVE;
    326 
    327 	/* Establish the interrupt handler. */
    328 	sc->sc_isr.isr_ipl = hd->hp_ipl;
    329 	sc->sc_isr.isr_arg = brd;
    330 	sc->sc_isr.isr_intr = dcmintr;
    331 	isrlink(&sc->sc_isr);
    332 
    333 	if (dcmistype == DIS_TIMER)
    334 		dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
    335 	else
    336 		dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
    337 
    338 	/* load pointers to modem control */
    339 	sc->sc_modem[0] = &dcm->dcm_modem0;
    340 	sc->sc_modem[1] = &dcm->dcm_modem1;
    341 	sc->sc_modem[2] = &dcm->dcm_modem2;
    342 	sc->sc_modem[3] = &dcm->dcm_modem3;
    343 
    344 	/* set DCD (modem) and CTS (flow control) on all ports */
    345 	if (sc->sc_flags & DCM_STDDCE)
    346 		mbits = hp2dce_in(MI_CD|MI_CTS);
    347 	else
    348 		mbits = MI_CD|MI_CTS;
    349 
    350 	for (i = 0; i < NDCMPORT; i++)
    351 		sc->sc_modem[i]->mdmmsk = mbits;
    352 
    353 	dcm->dcm_ic = IC_IE;		/* turn all interrupts on */
    354 
    355 	/*
    356 	 * Need to reset baud rate, etc. of next print so reset dcmconsole.
    357 	 * Also make sure console is always "hardwired"
    358 	 */
    359 	if (isconsole) {
    360 		dcmconsinit = 0;
    361 		sc->sc_softCAR |= (1 << DCMPORT(dcmconsole));
    362 		printf(": console on port %d\n", DCMPORT(dcmconsole));
    363 	} else
    364 		printf("\n");
    365 
    366 #ifdef KGDB
    367 	if (major(kgdb_dev) == dcmmajor &&
    368 	    DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
    369 		if (dcmconsole == DCMUNIT(kgdb_dev))
    370 			kgdb_dev = NODEV; /* can't debug over console port */
    371 #ifndef KGDB_CHEAT
    372 		/*
    373 		 * The following could potentially be replaced
    374 		 * by the corresponding code in dcmcnprobe.
    375 		 */
    376 		else {
    377 			(void) dcminit(kgdb_dev, kgdb_rate);
    378 			if (kgdb_debug_init) {
    379 				printf("%s port %d: ", sc->sc_hd->hp_xname,
    380 				    DCMPORT(DCMUNIT(kgdb_dev)));
    381 				kgdb_connect(1);
    382 			} else
    383 				printf("%s port %d: kgdb enabled\n",
    384 				    sc->sc_hd->hp_xname,
    385 				    DCMPORT(DCMUNIT(kgdb_dev)));
    386 		}
    387 		/* end could be replaced */
    388 #endif
    389 	}
    390 #endif
    391 }
    392 
    393 /* ARGSUSED */
    394 int
    395 dcmopen(dev, flag, mode, p)
    396 	dev_t dev;
    397 	int flag, mode;
    398 	struct proc *p;
    399 {
    400 	struct dcm_softc *sc;
    401 	struct tty *tp;
    402 	int unit, brd, port;
    403 	int error = 0, mbits, s;
    404 
    405 	unit = DCMUNIT(dev);
    406 	brd = DCMBOARD(unit);
    407 	port = DCMPORT(unit);
    408 
    409 	if ((brd >= NDCM) || (port >= NDCMPORT))
    410 		return (ENXIO);
    411 
    412 	sc = &dcm_softc[brd];
    413 	if ((sc->sc_flags & DCM_ACTIVE) == 0)
    414 		return (ENXIO);
    415 
    416 	if (sc->sc_tty[port] == NULL)
    417 		tp = sc->sc_tty[port] = ttymalloc();
    418 	else
    419 		tp = sc->sc_tty[port];
    420 
    421 	tp->t_oproc = dcmstart;
    422 	tp->t_param = dcmparam;
    423 	tp->t_dev = dev;
    424 
    425 	if ((tp->t_state & TS_ISOPEN) == 0) {
    426 		/*
    427 		 * Sanity clause: reset the card on first open.
    428 		 * The card might be left in an inconsistent state
    429 		 * if the card memory is read inadvertently.
    430 		 */
    431 		dcminit(dev, dcmdefaultrate);
    432 
    433 		tp->t_state |= TS_WOPEN;
    434 		ttychars(tp);
    435 		tp->t_iflag = TTYDEF_IFLAG;
    436 		tp->t_oflag = TTYDEF_OFLAG;
    437 		tp->t_cflag = TTYDEF_CFLAG;
    438 		tp->t_lflag = TTYDEF_LFLAG;
    439 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
    440 
    441 		s = spltty();
    442 
    443 		(void) dcmparam(tp, &tp->t_termios);
    444 		ttsetwater(tp);
    445 	} else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0)
    446 		return (EBUSY);
    447 	else
    448 		s = spltty();
    449 
    450 	/* Set modem control state. */
    451 	mbits = MO_ON;
    452 	if (sc->sc_flags & DCM_STDDCE)
    453 		mbits |= MO_SR;		/* pin 23, could be used as RTS */
    454 
    455 	(void) dcmmctl(dev, mbits, DMSET);	/* enable port */
    456 
    457 	/* Set soft-carrier if so configured. */
    458 	if ((sc->sc_softCAR & (1 << port)) ||
    459 	    (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
    460 		tp->t_state |= TS_CARR_ON;
    461 
    462 #ifdef DEBUG
    463 	if (dcmdebug & DDB_MODEM)
    464 		printf("%s: dcmopen port %d softcarr %c\n",
    465 		       sc->sc_hd->hp_xname, port,
    466 		       (tp->t_state & TS_CARR_ON) ? '1' : '0');
    467 #endif
    468 
    469 	/* Wait for carrier if necessary. */
    470 	if ((flag & O_NONBLOCK) == 0)
    471 		while ((tp->t_cflag & CLOCAL) == 0 &&
    472 		    (tp->t_state & TS_CARR_ON) == 0) {
    473 			tp->t_state |= TS_WOPEN;
    474 			error = ttysleep(tp, (caddr_t)&tp->t_rawq,
    475 			    TTIPRI | PCATCH, ttopen, 0);
    476 			if (error) {
    477 				splx(s);
    478 				return (error);
    479 			}
    480 		}
    481 
    482 	splx(s);
    483 
    484 #ifdef DEBUG
    485 	if (dcmdebug & DDB_OPENCLOSE)
    486 		printf("%s port %d: dcmopen: st %x fl %x\n",
    487 			sc->sc_hd->hp_xname, port, tp->t_state, tp->t_flags);
    488 #endif
    489 	if (error == 0)
    490 		error = (*linesw[tp->t_line].l_open)(dev, tp);
    491 
    492 	return (error);
    493 }
    494 
    495 /*ARGSUSED*/
    496 int
    497 dcmclose(dev, flag, mode, p)
    498 	dev_t dev;
    499 	int flag, mode;
    500 	struct proc *p;
    501 {
    502 	int s, unit, board, port;
    503 	struct dcm_softc *sc;
    504 	struct tty *tp;
    505 
    506 	unit = DCMUNIT(dev);
    507 	board = DCMBOARD(unit);
    508 	port = DCMPORT(unit);
    509 
    510 	sc = &dcm_softc[board];
    511 	tp = sc->sc_tty[port];
    512 
    513 	(*linesw[tp->t_line].l_close)(tp, flag);
    514 
    515 	s = spltty();
    516 
    517 	if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN ||
    518 	    (tp->t_state & TS_ISOPEN) == 0)
    519 		(void) dcmmctl(dev, MO_OFF, DMSET);
    520 #ifdef DEBUG
    521 	if (dcmdebug & DDB_OPENCLOSE)
    522 		printf("%s port %d: dcmclose: st %x fl %x\n",
    523 			sc->sc_hd->hp_xname, port, tp->t_state, tp->t_flags);
    524 #endif
    525 	splx(s);
    526 	ttyclose(tp);
    527 #if 0
    528 	ttyfree(tp);
    529 	sc->sc_tty[port] == NULL;
    530 #endif
    531 	return (0);
    532 }
    533 
    534 int
    535 dcmread(dev, uio, flag)
    536 	dev_t dev;
    537 	struct uio *uio;
    538 	int flag;
    539 {
    540 	int unit, board, port;
    541 	struct dcm_softc *sc;
    542 	register struct tty *tp;
    543 
    544 	unit = DCMUNIT(dev);
    545 	board = DCMBOARD(unit);
    546 	port = DCMPORT(unit);
    547 
    548 	sc = &dcm_softc[board];
    549 	tp = sc->sc_tty[port];
    550 
    551 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
    552 }
    553 
    554 int
    555 dcmwrite(dev, uio, flag)
    556 	dev_t dev;
    557 	struct uio *uio;
    558 	int flag;
    559 {
    560 	int unit, board, port;
    561 	struct dcm_softc *sc;
    562 	register struct tty *tp;
    563 
    564 	unit = DCMUNIT(dev);
    565 	board = DCMBOARD(unit);
    566 	port = DCMPORT(unit);
    567 
    568 	sc = &dcm_softc[board];
    569 	tp = sc->sc_tty[port];
    570 
    571 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
    572 }
    573 
    574 struct tty *
    575 dcmtty(dev)
    576 	dev_t dev;
    577 {
    578 	int unit, board, port;
    579 	struct dcm_softc *sc;
    580 
    581 	unit = DCMUNIT(dev);
    582 	board = DCMBOARD(unit);
    583 	port = DCMPORT(unit);
    584 
    585 	sc = &dcm_softc[board];
    586 
    587 	return (sc->sc_tty[port]);
    588 }
    589 
    590 int
    591 dcmintr(brd)
    592 	register int brd;
    593 {
    594 	struct dcm_softc *sc = &dcm_softc[brd];
    595 	struct dcmdevice *dcm = sc->sc_dcm;
    596 	struct dcmischeme *dis = &sc->sc_scheme;
    597 	int code, i;
    598 	int pcnd[4], mcode, mcnd[4];
    599 
    600 	/*
    601 	 * Do all guarded register accesses right off to minimize
    602 	 * block out of hardware.
    603 	 */
    604 	SEM_LOCK(dcm);
    605 	if ((dcm->dcm_ic & IC_IR) == 0) {
    606 		SEM_UNLOCK(dcm);
    607 		return (0);
    608 	}
    609 	for (i = 0; i < 4; i++) {
    610 		pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
    611 		dcm->dcm_icrtab[i].dcm_data = 0;
    612 		code = sc->sc_modem[i]->mdmin;
    613 		if (sc->sc_flags & DCM_STDDCE)
    614 			code = hp2dce_in(code);
    615 		mcnd[i] = code;
    616 	}
    617 	code = dcm->dcm_iir & IIR_MASK;
    618 	dcm->dcm_iir = 0;	/* XXX doc claims read clears interrupt?! */
    619 	mcode = dcm->dcm_modemintr;
    620 	dcm->dcm_modemintr = 0;
    621 	SEM_UNLOCK(dcm);
    622 
    623 #ifdef DEBUG
    624 	if (dcmdebug & DDB_INTR) {
    625 		printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
    626 		       sc->sc_hd->hp_xname, code, pcnd[0], pcnd[1],
    627 		       pcnd[2], pcnd[3]);
    628 		printf("miir %x mc %x/%x/%x/%x\n",
    629 		       mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
    630 	}
    631 #endif
    632 	if (code & IIR_TIMEO)
    633 		dcmrint(sc);
    634 	if (code & IIR_PORT0)
    635 		dcmpint(sc, 0, pcnd[0]);
    636 	if (code & IIR_PORT1)
    637 		dcmpint(sc, 1, pcnd[1]);
    638 	if (code & IIR_PORT2)
    639 		dcmpint(sc, 2, pcnd[2]);
    640 	if (code & IIR_PORT3)
    641 		dcmpint(sc, 3, pcnd[3]);
    642 	if (code & IIR_MODM) {
    643 		if (mcode == 0 || mcode & 0x1)	/* mcode==0 -> 98642 board */
    644 			dcmmint(sc, 0, mcnd[0]);
    645 		if (mcode & 0x2)
    646 			dcmmint(sc, 1, mcnd[1]);
    647 		if (mcode & 0x4)
    648 			dcmmint(sc, 2, mcnd[2]);
    649 		if (mcode & 0x8)
    650 			dcmmint(sc, 3, mcnd[3]);
    651 	}
    652 
    653 	/*
    654 	 * Chalk up a receiver interrupt if the timer running or one of
    655 	 * the ports reports a special character interrupt.
    656 	 */
    657 	if ((code & IIR_TIMEO) ||
    658 	    ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
    659 		dis->dis_intr++;
    660 	/*
    661 	 * See if it is time to check/change the interrupt rate.
    662 	 */
    663 	if (dcmistype < 0 &&
    664 	    (i = time.tv_sec - dis->dis_time) >= dcminterval) {
    665 		/*
    666 		 * If currently per-character and averaged over 70 interrupts
    667 		 * per-second (66 is threshold of 600 baud) in last interval,
    668 		 * switch to timer mode.
    669 		 *
    670 		 * XXX decay counts ala load average to avoid spikes?
    671 		 */
    672 		if (dis->dis_perchar && dis->dis_intr > 70 * i)
    673 			dcmsetischeme(brd, DIS_TIMER);
    674 		/*
    675 		 * If currently using timer and had more interrupts than
    676 		 * received characters in the last interval, switch back
    677 		 * to per-character.  Note that after changing to per-char
    678 		 * we must process any characters already in the queue
    679 		 * since they may have arrived before the bitmap was setup.
    680 		 *
    681 		 * XXX decay counts?
    682 		 */
    683 		else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
    684 			dcmsetischeme(brd, DIS_PERCHAR);
    685 			dcmrint(sc);
    686 		}
    687 		dis->dis_intr = dis->dis_char = 0;
    688 		dis->dis_time = time.tv_sec;
    689 	}
    690 	return (1);
    691 }
    692 
    693 /*
    694  *  Port interrupt.  Can be two things:
    695  *	First, it might be a special character (exception interrupt);
    696  *	Second, it may be a buffer empty (transmit interrupt);
    697  */
    698 dcmpint(sc, port, code)
    699 	struct dcm_softc *sc;
    700 	int port, code;
    701 {
    702 
    703 	if (code & IT_SPEC)
    704 		dcmreadbuf(sc, port);
    705 	if (code & IT_TX)
    706 		dcmxint(sc, port);
    707 }
    708 
    709 dcmrint(sc)
    710 	struct dcm_softc *sc;
    711 {
    712 	int port;
    713 
    714 	for (port = 0; port < NDCMPORT; port++)
    715 		dcmreadbuf(sc, port);
    716 }
    717 
    718 dcmreadbuf(sc, port)
    719 	struct dcm_softc *sc;
    720 	int port;
    721 {
    722 	struct dcmdevice *dcm = sc->sc_dcm;
    723 	struct tty *tp = sc->sc_tty[port];
    724 	struct dcmpreg *pp = dcm_preg(dcm, port);
    725 	struct dcmrfifo *fifo;
    726 	int c, stat;
    727 	u_int head;
    728 	int nch = 0;
    729 #ifdef DCMSTATS
    730 	struct dcmstats *dsp = &sc->sc_stats;
    731 
    732 	dsp->rints++;
    733 #endif
    734 	if ((tp->t_state & TS_ISOPEN) == 0) {
    735 #ifdef KGDB
    736 		if ((makedev(dcmmajor, minor(tp->t_dev)) == kgdb_dev) &&
    737 		    (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
    738 		    dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
    739 			pp->r_head = (head + 2) & RX_MASK;
    740 			kgdb_connect(0);	/* trap into kgdb */
    741 			return;
    742 		}
    743 #endif /* KGDB */
    744 		pp->r_head = pp->r_tail & RX_MASK;
    745 		return;
    746 	}
    747 
    748 	head = pp->r_head & RX_MASK;
    749 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
    750 	/*
    751 	 * XXX upper bound on how many chars we will take in one swallow?
    752 	 */
    753 	while (head != (pp->r_tail & RX_MASK)) {
    754 		/*
    755 		 * Get character/status and update head pointer as fast
    756 		 * as possible to make room for more characters.
    757 		 */
    758 		c = fifo->data_char;
    759 		stat = fifo->data_stat;
    760 		head = (head + 2) & RX_MASK;
    761 		pp->r_head = head;
    762 		fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
    763 		nch++;
    764 
    765 #ifdef DEBUG
    766 		if (dcmdebug & DDB_INPUT)
    767 			printf("%s port %d: dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
    768 			       sc->sc_hd->hp_xname, port,
    769 			       c&0xFF, c, stat&0xFF,
    770 			       tp->t_flags, head, pp->r_tail);
    771 #endif
    772 		/*
    773 		 * Check for and handle errors
    774 		 */
    775 		if (stat & RD_MASK) {
    776 #ifdef DEBUG
    777 			if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
    778 				printf("%s port %d: dcmreadbuf: err: c%x('%c') s%x\n",
    779 				       sc->sc_hd->hp_xname, port,
    780 				       stat, c&0xFF, c);
    781 #endif
    782 			if (stat & (RD_BD | RD_FE))
    783 				c |= TTY_FE;
    784 			else if (stat & RD_PE)
    785 				c |= TTY_PE;
    786 			else if (stat & RD_OVF)
    787 				log(LOG_WARNING,
    788 				    "%s port %d: silo overflow\n",
    789 				    sc->sc_hd->hp_xname, port);
    790 			else if (stat & RD_OE)
    791 				log(LOG_WARNING,
    792 				    "%s port %d: uart overflow\n",
    793 				    sc->sc_hd->hp_xname, port);
    794 		}
    795 		(*linesw[tp->t_line].l_rint)(c, tp);
    796 	}
    797 	sc->sc_scheme.dis_char += nch;
    798 
    799 #ifdef DCMSTATS
    800 	dsp->rchars += nch;
    801 	if (nch <= DCMRBSIZE)
    802 		dsp->rsilo[nch]++;
    803 	else
    804 		dsp->rsilo[DCMRBSIZE+1]++;
    805 #endif
    806 }
    807 
    808 dcmxint(sc, port)
    809 	struct dcm_softc *sc;
    810 	int port;
    811 {
    812 	struct tty *tp = sc->sc_tty[port];
    813 
    814 	tp->t_state &= ~TS_BUSY;
    815 	if (tp->t_state & TS_FLUSH)
    816 		tp->t_state &= ~TS_FLUSH;
    817 	(*linesw[tp->t_line].l_start)(tp);
    818 }
    819 
    820 dcmmint(sc, port, mcnd)
    821 	struct dcm_softc *sc;
    822 	int port, mcnd;
    823 {
    824 	int delta;
    825 	struct tty *tp;
    826 	struct dcmdevice *dcm = sc->sc_dcm;
    827 
    828 	tp = sc->sc_tty[port];
    829 
    830 #ifdef DEBUG
    831 	if (dcmdebug & DDB_MODEM)
    832 		printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
    833 		       sc->sc_hd->hp_xname, port, mcnd, sc->sc_mcndlast[port]);
    834 #endif
    835 	delta = mcnd ^ sc->sc_mcndlast[port];
    836 	sc->sc_mcndlast[port] = mcnd;
    837 	if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
    838 	    (tp->t_flags & CCTS_OFLOW)) {
    839 		if (mcnd & MI_CTS) {
    840 			tp->t_state &= ~TS_TTSTOP;
    841 			ttstart(tp);
    842 		} else
    843 			tp->t_state |= TS_TTSTOP;	/* inline dcmstop */
    844 	}
    845 	if (delta & MI_CD) {
    846 		if (mcnd & MI_CD)
    847 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
    848 		else if ((sc->sc_softCAR & (1 << port)) == 0 &&
    849 		    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
    850 			sc->sc_modem[port]->mdmout = MO_OFF;
    851 			SEM_LOCK(dcm);
    852 			dcm->dcm_modemchng |= (1 << port);
    853 			dcm->dcm_cr |= CR_MODM;
    854 			SEM_UNLOCK(dcm);
    855 			DELAY(10); /* time to change lines */
    856 		}
    857 	}
    858 }
    859 
    860 int
    861 dcmioctl(dev, cmd, data, flag, p)
    862 	dev_t dev;
    863 	int cmd;
    864 	caddr_t data;
    865 	int flag;
    866 	struct proc *p;
    867 {
    868 	struct dcm_softc *sc;
    869 	struct tty *tp;
    870 	struct dcmdevice *dcm;
    871 	int board, port, unit = DCMUNIT(dev);
    872 	int error, s;
    873 
    874 	port = DCMPORT(unit);
    875 	board = DCMBOARD(unit);
    876 
    877 	sc = &dcm_softc[board];
    878 	dcm = sc->sc_dcm;
    879 	tp = sc->sc_tty[port];
    880 
    881 #ifdef DEBUG
    882 	if (dcmdebug & DDB_IOCTL)
    883 		printf("%s port %d: dcmioctl: cmd %x data %x flag %x\n",
    884 		       sc->sc_hd->hp_xname, port, cmd, *data, flag);
    885 #endif
    886 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
    887 	if (error >= 0)
    888 		return (error);
    889 	error = ttioctl(tp, cmd, data, flag, p);
    890 	if (error >= 0)
    891 		return (error);
    892 
    893 	switch (cmd) {
    894 	case TIOCSBRK:
    895 		/*
    896 		 * Wait for transmitter buffer to empty
    897 		 */
    898 		s = spltty();
    899 		while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
    900 			DELAY(DCM_USPERCH(tp->t_ospeed));
    901 		SEM_LOCK(dcm);
    902 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
    903 		dcm->dcm_cr |= (1 << port);	/* start break */
    904 		SEM_UNLOCK(dcm);
    905 		splx(s);
    906 		break;
    907 
    908 	case TIOCCBRK:
    909 		SEM_LOCK(dcm);
    910 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
    911 		dcm->dcm_cr |= (1 << port);	/* end break */
    912 		SEM_UNLOCK(dcm);
    913 		break;
    914 
    915 	case TIOCSDTR:
    916 		(void) dcmmctl(dev, MO_ON, DMBIS);
    917 		break;
    918 
    919 	case TIOCCDTR:
    920 		(void) dcmmctl(dev, MO_ON, DMBIC);
    921 		break;
    922 
    923 	case TIOCMSET:
    924 		(void) dcmmctl(dev, *(int *)data, DMSET);
    925 		break;
    926 
    927 	case TIOCMBIS:
    928 		(void) dcmmctl(dev, *(int *)data, DMBIS);
    929 		break;
    930 
    931 	case TIOCMBIC:
    932 		(void) dcmmctl(dev, *(int *)data, DMBIC);
    933 		break;
    934 
    935 	case TIOCMGET:
    936 		*(int *)data = dcmmctl(dev, 0, DMGET);
    937 		break;
    938 
    939 	case TIOCGFLAGS: {
    940 		int bits = 0;
    941 
    942 		if ((sc->sc_softCAR & (1 << port)))
    943 			bits |= TIOCFLAG_SOFTCAR;
    944 
    945 		if (tp->t_cflag & CLOCAL)
    946 			bits |= TIOCFLAG_CLOCAL;
    947 
    948 		*(int *)data = bits;
    949 		break;
    950 	}
    951 
    952 	case TIOCSFLAGS: {
    953 		int userbits;
    954 
    955 		error = suser(p->p_ucred, &p->p_acflag);
    956 		if (error)
    957 			return (EPERM);
    958 
    959 		userbits = *(int *)data;
    960 
    961 		if ((userbits & TIOCFLAG_SOFTCAR) ||
    962 		    ((board == DCMBOARD(dcmconsole)) &&
    963 		    (port == DCMPORT(dcmconsole))))
    964 			sc->sc_softCAR |= (1 << port);
    965 
    966 		if (userbits & TIOCFLAG_CLOCAL)
    967 			tp->t_cflag |= CLOCAL;
    968 
    969 		break;
    970 	}
    971 
    972 	default:
    973 		return (ENOTTY);
    974 	}
    975 	return (0);
    976 }
    977 
    978 int
    979 dcmparam(tp, t)
    980 	register struct tty *tp;
    981 	register struct termios *t;
    982 {
    983 	struct dcm_softc *sc;
    984 	struct dcmdevice *dcm;
    985 	int unit, board, port, mode, cflag = t->c_cflag;
    986 	int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
    987 
    988 	unit = DCMUNIT(tp->t_dev);
    989 	board = DCMBOARD(unit);
    990 	port = DCMPORT(unit);
    991 
    992 	sc = &dcm_softc[board];
    993 	dcm = sc->sc_dcm;
    994 
    995 	/* check requested parameters */
    996         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
    997                 return (EINVAL);
    998         /* and copy to tty */
    999         tp->t_ispeed = t->c_ispeed;
   1000         tp->t_ospeed = t->c_ospeed;
   1001         tp->t_cflag = cflag;
   1002 	if (ospeed == 0) {
   1003 		(void) dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
   1004 		return (0);
   1005 	}
   1006 
   1007 	mode = 0;
   1008 	switch (cflag&CSIZE) {
   1009 	case CS5:
   1010 		mode = LC_5BITS; break;
   1011 	case CS6:
   1012 		mode = LC_6BITS; break;
   1013 	case CS7:
   1014 		mode = LC_7BITS; break;
   1015 	case CS8:
   1016 		mode = LC_8BITS; break;
   1017 	}
   1018 	if (cflag&PARENB) {
   1019 		if (cflag&PARODD)
   1020 			mode |= LC_PODD;
   1021 		else
   1022 			mode |= LC_PEVEN;
   1023 	}
   1024 	if (cflag&CSTOPB)
   1025 		mode |= LC_2STOP;
   1026 	else
   1027 		mode |= LC_1STOP;
   1028 #ifdef DEBUG
   1029 	if (dcmdebug & DDB_PARAM)
   1030 		printf("%s port %d: dcmparam: cflag %x mode %x speed %d uperch %d\n",
   1031 		       sc->sc_hd->hp_xname, port, cflag, mode, tp->t_ospeed,
   1032 		       DCM_USPERCH(tp->t_ospeed));
   1033 #endif
   1034 
   1035 	/*
   1036 	 * Wait for transmitter buffer to empty.
   1037 	 */
   1038 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
   1039 		DELAY(DCM_USPERCH(tp->t_ospeed));
   1040 	/*
   1041 	 * Make changes known to hardware.
   1042 	 */
   1043 	dcm->dcm_data[port].dcm_baud = ospeed;
   1044 	dcm->dcm_data[port].dcm_conf = mode;
   1045 	SEM_LOCK(dcm);
   1046 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
   1047 	dcm->dcm_cr |= (1 << port);
   1048 	SEM_UNLOCK(dcm);
   1049 	/*
   1050 	 * Delay for config change to take place. Weighted by baud.
   1051 	 * XXX why do we do this?
   1052 	 */
   1053 	DELAY(16 * DCM_USPERCH(tp->t_ospeed));
   1054 	return (0);
   1055 }
   1056 
   1057 void
   1058 dcmstart(tp)
   1059 	register struct tty *tp;
   1060 {
   1061 	struct dcm_softc *sc;
   1062 	struct dcmdevice *dcm;
   1063 	struct dcmpreg *pp;
   1064 	struct dcmtfifo *fifo;
   1065 	char *bp;
   1066 	u_int head, tail, next;
   1067 	int unit, board, port, nch;
   1068 	char buf[16];
   1069 	int s;
   1070 #ifdef DCMSTATS
   1071 	struct dcmstats *dsp = &sc->sc_stats;
   1072 	int tch = 0;
   1073 #endif
   1074 
   1075 	unit = DCMUNIT(tp->t_dev);
   1076 	board = DCMBOARD(unit);
   1077 	port = DCMPORT(unit);
   1078 
   1079 	sc = &dcm_softc[board];
   1080 	dcm = sc->sc_dcm;
   1081 
   1082 	s = spltty();
   1083 #ifdef DCMSTATS
   1084 	dsp->xints++;
   1085 #endif
   1086 #ifdef DEBUG
   1087 	if (dcmdebug & DDB_OUTPUT)
   1088 		printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
   1089 		       sc->sc_hd->hp_xname, port, tp->t_state, tp->t_flags,
   1090 		       tp->t_outq.c_cc);
   1091 #endif
   1092 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
   1093 		goto out;
   1094 	if (tp->t_outq.c_cc <= tp->t_lowat) {
   1095 		if (tp->t_state&TS_ASLEEP) {
   1096 			tp->t_state &= ~TS_ASLEEP;
   1097 			wakeup((caddr_t)&tp->t_outq);
   1098 		}
   1099 		selwakeup(&tp->t_wsel);
   1100 	}
   1101 	if (tp->t_outq.c_cc == 0) {
   1102 #ifdef DCMSTATS
   1103 		dsp->xempty++;
   1104 #endif
   1105 		goto out;
   1106 	}
   1107 
   1108 	pp = dcm_preg(dcm, port);
   1109 	tail = pp->t_tail & TX_MASK;
   1110 	next = (tail + 1) & TX_MASK;
   1111 	head = pp->t_head & TX_MASK;
   1112 	if (head == next)
   1113 		goto out;
   1114 	fifo = &dcm->dcm_tfifos[3-port][tail];
   1115 again:
   1116 	nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
   1117 #ifdef DCMSTATS
   1118 	tch += nch;
   1119 #endif
   1120 #ifdef DEBUG
   1121 	if (dcmdebug & DDB_OUTPUT)
   1122 		printf("\thead %x tail %x nch %d\n", head, tail, nch);
   1123 #endif
   1124 	/*
   1125 	 * Loop transmitting all the characters we can.
   1126 	 */
   1127 	for (bp = buf; --nch >= 0; bp++) {
   1128 		fifo->data_char = *bp;
   1129 		pp->t_tail = next;
   1130 		/*
   1131 		 * If this is the first character,
   1132 		 * get the hardware moving right now.
   1133 		 */
   1134 		if (bp == buf) {
   1135 			tp->t_state |= TS_BUSY;
   1136 			SEM_LOCK(dcm);
   1137 			dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
   1138 			dcm->dcm_cr |= (1 << port);
   1139 			SEM_UNLOCK(dcm);
   1140 		}
   1141 		tail = next;
   1142 		fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
   1143 		next = (next + 1) & TX_MASK;
   1144 	}
   1145 	/*
   1146 	 * Head changed while we were loading the buffer,
   1147 	 * go back and load some more if we can.
   1148 	 */
   1149 	if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
   1150 #ifdef DCMSTATS
   1151 		dsp->xrestarts++;
   1152 #endif
   1153 		head = pp->t_head & TX_MASK;
   1154 		goto again;
   1155 	}
   1156 
   1157 	/*
   1158 	 * Kick it one last time in case it finished while we were
   1159 	 * loading the last bunch.
   1160 	 */
   1161 	if (bp > &buf[1]) {
   1162 		tp->t_state |= TS_BUSY;
   1163 		SEM_LOCK(dcm);
   1164 		dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
   1165 		dcm->dcm_cr |= (1 << port);
   1166 		SEM_UNLOCK(dcm);
   1167 	}
   1168 #ifdef DEBUG
   1169 	if (dcmdebug & DDB_INTR)
   1170 		printf("%s port %d: dcmstart(%d): head %x tail %x outqcc %d\n",
   1171 		    sc->sc_hd->hp_xname, port, head, tail, tp->t_outq.c_cc);
   1172 #endif
   1173 out:
   1174 #ifdef DCMSTATS
   1175 	dsp->xchars += tch;
   1176 	if (tch <= DCMXBSIZE)
   1177 		dsp->xsilo[tch]++;
   1178 	else
   1179 		dsp->xsilo[DCMXBSIZE+1]++;
   1180 #endif
   1181 	splx(s);
   1182 }
   1183 
   1184 /*
   1185  * Stop output on a line.
   1186  */
   1187 int
   1188 dcmstop(tp, flag)
   1189 	register struct tty *tp;
   1190 	int flag;
   1191 {
   1192 	int s;
   1193 
   1194 	s = spltty();
   1195 	if (tp->t_state & TS_BUSY) {
   1196 		/* XXX is there some way to safely stop transmission? */
   1197 		if ((tp->t_state&TS_TTSTOP) == 0)
   1198 			tp->t_state |= TS_FLUSH;
   1199 	}
   1200 	splx(s);
   1201 }
   1202 
   1203 /*
   1204  * Modem control
   1205  */
   1206 dcmmctl(dev, bits, how)
   1207 	dev_t dev;
   1208 	int bits, how;
   1209 {
   1210 	struct dcm_softc *sc;
   1211 	struct dcmdevice *dcm;
   1212 	int s, unit, brd, port, hit = 0;
   1213 
   1214 	unit = DCMUNIT(dev);
   1215 	brd = DCMBOARD(unit);
   1216 	port = DCMPORT(unit);
   1217 	sc = &dcm_softc[brd];
   1218 	dcm = sc->sc_dcm;
   1219 
   1220 #ifdef DEBUG
   1221 	if (dcmdebug & DDB_MODEM)
   1222 		printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
   1223 		       sc->sc_hd->hp_xname, port, bits, how);
   1224 #endif
   1225 
   1226 	s = spltty();
   1227 
   1228 	switch (how) {
   1229 	case DMSET:
   1230 		sc->sc_modem[port]->mdmout = bits;
   1231 		hit++;
   1232 		break;
   1233 
   1234 	case DMBIS:
   1235 		sc->sc_modem[port]->mdmout |= bits;
   1236 		hit++;
   1237 		break;
   1238 
   1239 	case DMBIC:
   1240 		sc->sc_modem[port]->mdmout &= ~bits;
   1241 		hit++;
   1242 		break;
   1243 
   1244 	case DMGET:
   1245 		bits = sc->sc_modem[port]->mdmin;
   1246 		if (sc->sc_flags & DCM_STDDCE)
   1247 			bits = hp2dce_in(bits);
   1248 		break;
   1249 	}
   1250 	if (hit) {
   1251 		SEM_LOCK(dcm);
   1252 		dcm->dcm_modemchng |= 1<<(unit & 3);
   1253 		dcm->dcm_cr |= CR_MODM;
   1254 		SEM_UNLOCK(dcm);
   1255 		DELAY(10); /* delay until done */
   1256 		(void) splx(s);
   1257 	}
   1258 	return (bits);
   1259 }
   1260 
   1261 /*
   1262  * Set board to either interrupt per-character or at a fixed interval.
   1263  */
   1264 dcmsetischeme(brd, flags)
   1265 	int brd, flags;
   1266 {
   1267 	struct dcm_softc *sc = &dcm_softc[brd];
   1268 	struct dcmdevice *dcm = sc->sc_dcm;
   1269 	struct dcmischeme *dis = &sc->sc_scheme;
   1270 	int i;
   1271 	u_char mask;
   1272 	int perchar = flags & DIS_PERCHAR;
   1273 
   1274 #ifdef DEBUG
   1275 	if (dcmdebug & DDB_INTSCHM)
   1276 		printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
   1277 		       sc->sc_hd->hp_xname, perchar, dis->dis_perchar,
   1278 		       dis->dis_intr, dis->dis_char);
   1279 	if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
   1280 		printf("%s: dcmsetischeme: redundent request %d\n",
   1281 		       sc->sc_hd->hp_xname, perchar);
   1282 		return;
   1283 	}
   1284 #endif
   1285 	/*
   1286 	 * If perchar is non-zero, we enable interrupts on all characters
   1287 	 * otherwise we disable perchar interrupts and use periodic
   1288 	 * polling interrupts.
   1289 	 */
   1290 	dis->dis_perchar = perchar;
   1291 	mask = perchar ? 0xf : 0x0;
   1292 	for (i = 0; i < 256; i++)
   1293 		dcm->dcm_bmap[i].data_data = mask;
   1294 	/*
   1295 	 * Don't slow down tandem mode, interrupt on flow control
   1296 	 * chars for any port on the board.
   1297 	 */
   1298 	if (!perchar) {
   1299 		register struct tty *tp;
   1300 		int c;
   1301 
   1302 		for (i = 0; i < NDCMPORT; i++) {
   1303 			tp = sc->sc_tty[i];
   1304 
   1305 			if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
   1306 				dcm->dcm_bmap[c].data_data |= (1 << i);
   1307 			if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
   1308 				dcm->dcm_bmap[c].data_data |= (1 << i);
   1309 		}
   1310 	}
   1311 	/*
   1312 	 * Board starts with timer disabled so if first call is to
   1313 	 * set perchar mode then we don't want to toggle the timer.
   1314 	 */
   1315 	if (flags == (DIS_RESET|DIS_PERCHAR))
   1316 		return;
   1317 	/*
   1318 	 * Toggle card 16.7ms interrupts (we first make sure that card
   1319 	 * has cleared the bit so it will see the toggle).
   1320 	 */
   1321 	while (dcm->dcm_cr & CR_TIMER)
   1322 		;
   1323 	SEM_LOCK(dcm);
   1324 	dcm->dcm_cr |= CR_TIMER;
   1325 	SEM_UNLOCK(dcm);
   1326 }
   1327 
   1328 /*
   1329  * Following are all routines needed for DCM to act as console
   1330  */
   1331 #include <dev/cons.h>
   1332 
   1333 void
   1334 dcmcnprobe(cp)
   1335 	struct consdev *cp;
   1336 {
   1337 	struct dcm_softc *sc;
   1338 	struct dcmdevice *dcm;
   1339 	struct hp_hw *hw;
   1340 	int unit;
   1341 
   1342 	/* locate the major number */
   1343 	for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)
   1344 		if (cdevsw[dcmmajor].d_open == dcmopen)
   1345 			break;
   1346 
   1347 	/*
   1348 	 * Implicitly assigns the lowest select code DCM card found to be
   1349 	 * logical unit 0 (actually CONUNIT).  If your config file does
   1350 	 * anything different, you're screwed.
   1351 	 */
   1352 	for (hw = sc_table; hw->hw_type; hw++)
   1353 		if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva))
   1354 			break;
   1355 	if (!HW_ISDEV(hw, D_COMMDCM)) {
   1356 		cp->cn_pri = CN_DEAD;
   1357 		return;
   1358 	}
   1359 
   1360 	unit = CONUNIT;
   1361 	sc = &dcm_softc[DCMBOARD(CONUNIT)];
   1362 	dcm = sc->sc_dcm = (struct dcmdevice *)hw->hw_kva;
   1363 
   1364 	/* initialize required fields */
   1365 	cp->cn_dev = makedev(dcmmajor, unit);
   1366 	switch (dcm->dcm_rsid) {
   1367 	case DCMID:
   1368 		cp->cn_pri = CN_NORMAL;
   1369 		break;
   1370 
   1371 	case DCMID|DCMCON:
   1372 		cp->cn_pri = CN_REMOTE;
   1373 		break;
   1374 
   1375 	default:
   1376 		cp->cn_pri = CN_DEAD;
   1377 		return;
   1378 	}
   1379 
   1380 	/*
   1381 	 * If dcmconsole is initialized, raise our priority.
   1382 	 */
   1383 	if (dcmconsole == unit)
   1384 		cp->cn_pri = CN_REMOTE;
   1385 #ifdef KGDB_CHEAT
   1386 	/*
   1387 	 * This doesn't currently work, at least not with ite consoles;
   1388 	 * the console hasn't been initialized yet.
   1389 	 */
   1390 	if (major(kgdb_dev) == dcmmajor &&
   1391 	    DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
   1392 		(void) dcminit(kgdb_dev, kgdb_rate);
   1393 		if (kgdb_debug_init) {
   1394 			/*
   1395 			 * We assume that console is ready for us...
   1396 			 * this assumes that a dca or ite console
   1397 			 * has been selected already and will init
   1398 			 * on the first putc.
   1399 			 */
   1400 			printf("dcm%d: ", DCMUNIT(kgdb_dev));
   1401 			kgdb_connect(1);
   1402 		}
   1403 	}
   1404 #endif
   1405 }
   1406 
   1407 void
   1408 dcmcninit(cp)
   1409 	struct consdev *cp;
   1410 {
   1411 
   1412 	dcminit(cp->cn_dev, dcmdefaultrate);
   1413 	dcmconsinit = 1;
   1414 	dcmconsole = DCMUNIT(cp->cn_dev);
   1415 }
   1416 
   1417 dcminit(dev, rate)
   1418 	dev_t dev;
   1419 	int rate;
   1420 {
   1421 	struct dcm_softc *sc;
   1422 	struct dcmdevice *dcm;
   1423 	int s, mode, unit, board, port;
   1424 
   1425 	unit = DCMUNIT(dev);
   1426 	board = DCMBOARD(unit);
   1427 	port = DCMPORT(unit);
   1428 
   1429 	sc = &dcm_softc[board];
   1430 	dcm = sc->sc_dcm;
   1431 
   1432 	mode = LC_8BITS | LC_1STOP;
   1433 
   1434 	s = splhigh();
   1435 
   1436 	/*
   1437 	 * Wait for transmitter buffer to empty.
   1438 	 */
   1439 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
   1440 		DELAY(DCM_USPERCH(rate));
   1441 
   1442 	/*
   1443 	 * Make changes known to hardware.
   1444 	 */
   1445 	dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
   1446 	dcm->dcm_data[port].dcm_conf = mode;
   1447 	SEM_LOCK(dcm);
   1448 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
   1449 	dcm->dcm_cr |= (1 << port);
   1450 	SEM_UNLOCK(dcm);
   1451 
   1452 	/*
   1453 	 * Delay for config change to take place. Weighted by baud.
   1454 	 * XXX why do we do this?
   1455 	 */
   1456 	DELAY(16 * DCM_USPERCH(rate));
   1457 	splx(s);
   1458 }
   1459 
   1460 int
   1461 dcmcngetc(dev)
   1462 	dev_t dev;
   1463 {
   1464 	struct dcm_softc *sc;
   1465 	struct dcmdevice *dcm;
   1466 	struct dcmrfifo *fifo;
   1467 	struct dcmpreg *pp;
   1468 	u_int head;
   1469 	int s, c, stat, unit, board, port;
   1470 
   1471 	unit = DCMUNIT(dev);
   1472 	board = DCMBOARD(unit);
   1473 	port = DCMPORT(unit);
   1474 
   1475 	sc = &dcm_softc[board];
   1476 	dcm = sc->sc_dcm;
   1477 	pp = dcm_preg(dcm, port);
   1478 
   1479 	s = splhigh();
   1480 	head = pp->r_head & RX_MASK;
   1481 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
   1482 	while (head == (pp->r_tail & RX_MASK))
   1483 		;
   1484 	/*
   1485 	 * If board interrupts are enabled, just let our received char
   1486 	 * interrupt through in case some other port on the board was
   1487 	 * busy.  Otherwise we must clear the interrupt.
   1488 	 */
   1489 	SEM_LOCK(dcm);
   1490 	if ((dcm->dcm_ic & IC_IE) == 0)
   1491 		stat = dcm->dcm_iir;
   1492 	SEM_UNLOCK(dcm);
   1493 	c = fifo->data_char;
   1494 	stat = fifo->data_stat;
   1495 	pp->r_head = (head + 2) & RX_MASK;
   1496 	splx(s);
   1497 	return (c);
   1498 }
   1499 
   1500 /*
   1501  * Console kernel output character routine.
   1502  */
   1503 void
   1504 dcmcnputc(dev, c)
   1505 	dev_t dev;
   1506 	int c;
   1507 {
   1508 	struct dcm_softc *sc;
   1509 	struct dcmdevice *dcm;
   1510 	struct dcmpreg *pp;
   1511 	unsigned tail;
   1512 	int s, unit, board, port, stat;
   1513 
   1514 	unit = DCMUNIT(dev);
   1515 	board = DCMBOARD(unit);
   1516 	port = DCMPORT(unit);
   1517 
   1518 	sc = &dcm_softc[board];
   1519 	dcm = sc->sc_dcm;
   1520 	pp = dcm_preg(dcm, port);
   1521 
   1522 	s = splhigh();
   1523 #ifdef KGDB
   1524 	if (dev != kgdb_dev)
   1525 #endif
   1526 	if (dcmconsinit == 0) {
   1527 		(void) dcminit(dev, dcmdefaultrate);
   1528 		dcmconsinit = 1;
   1529 	}
   1530 	tail = pp->t_tail & TX_MASK;
   1531 	while (tail != (pp->t_head & TX_MASK))
   1532 		;
   1533 	dcm->dcm_tfifos[3-port][tail].data_char = c;
   1534 	pp->t_tail = tail = (tail + 1) & TX_MASK;
   1535 	SEM_LOCK(dcm);
   1536 	dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
   1537 	dcm->dcm_cr |= (1 << port);
   1538 	SEM_UNLOCK(dcm);
   1539 	while (tail != (pp->t_head & TX_MASK))
   1540 		;
   1541 	/*
   1542 	 * If board interrupts are enabled, just let our completion
   1543 	 * interrupt through in case some other port on the board
   1544 	 * was busy.  Otherwise we must clear the interrupt.
   1545 	 */
   1546 	if ((dcm->dcm_ic & IC_IE) == 0) {
   1547 		SEM_LOCK(dcm);
   1548 		stat = dcm->dcm_iir;
   1549 		SEM_UNLOCK(dcm);
   1550 	}
   1551 	splx(s);
   1552 }
   1553 #endif
   1554