xref: /csrg-svn/sys/hp/dev/dca.c (revision 63146)
141480Smckusick /*
2*63146Sbostic  * Copyright (c) 1982, 1986, 1990, 1993
3*63146Sbostic  *	The Regents of the University of California.  All rights reserved.
441480Smckusick  *
541480Smckusick  * %sccs.include.redist.c%
641480Smckusick  *
7*63146Sbostic  *	@(#)dca.c	8.1 (Berkeley) 06/10/93
841480Smckusick  */
941480Smckusick 
1041480Smckusick #include "dca.h"
1141480Smckusick #if NDCA > 0
1241480Smckusick /*
1353923Shibler  *  Driver for National Semiconductor INS8250/NS16550AF/WD16C552 UARTs.
1453923Shibler  *  Includes:
1553923Shibler  *	98626/98644/internal serial interface on hp300/hp400
1653923Shibler  *	internal serial ports on hp700
1753923Shibler  *
1853923Shibler  *  N.B. On the hp700, there is a "secret bit" with undocumented behavior.
1953923Shibler  *  The third bit of the Modem Control Register (MCR_IEN == 0x08) must be
2053923Shibler  *  set to enable interrupts.
2141480Smckusick  */
2256504Sbostic #include <sys/param.h>
2356504Sbostic #include <sys/systm.h>
2456504Sbostic #include <sys/ioctl.h>
2556504Sbostic #include <sys/proc.h>
2656504Sbostic #include <sys/tty.h>
2756504Sbostic #include <sys/conf.h>
2856504Sbostic #include <sys/file.h>
2956504Sbostic #include <sys/uio.h>
3056504Sbostic #include <sys/kernel.h>
3156504Sbostic #include <sys/syslog.h>
3241480Smckusick 
3356504Sbostic #include <hp/dev/device.h>
3456504Sbostic #include <hp/dev/dcareg.h>
3553923Shibler 
3656504Sbostic #include <machine/cpu.h>
3753923Shibler #ifdef hp300
3856504Sbostic #include <hp300/hp300/isr.h>
3953923Shibler #endif
4053923Shibler #ifdef hp700
4156504Sbostic #include <machine/asp.h>
4253923Shibler #endif
4341480Smckusick 
4441480Smckusick int	dcaprobe();
4541480Smckusick struct	driver dcadriver = {
4641480Smckusick 	dcaprobe, "dca",
4741480Smckusick };
4841480Smckusick 
4952389Smckusick void	dcastart();
5052389Smckusick int	dcaparam(), dcaintr();
5141480Smckusick int	dcasoftCAR;
5241480Smckusick int	dca_active;
5349300Shibler int	dca_hasfifo;
5441480Smckusick int	ndca = NDCA;
5549130Skarels #ifdef DCACONSOLE
5649130Skarels int	dcaconsole = DCACONSOLE;
5749130Skarels #else
5841480Smckusick int	dcaconsole = -1;
5949130Skarels #endif
6049130Skarels int	dcaconsinit;
6141480Smckusick int	dcadefaultrate = TTYDEF_SPEED;
6249130Skarels int	dcamajor;
6341480Smckusick struct	dcadevice *dca_addr[NDCA];
6441480Smckusick struct	tty dca_tty[NDCA];
6553923Shibler #ifdef hp300
6641480Smckusick struct	isr dcaisr[NDCA];
6757308Shibler int	dcafastservice;
6853923Shibler #endif
6957308Shibler int	dcaoflows[NDCA];
7041480Smckusick 
7141480Smckusick struct speedtab dcaspeedtab[] = {
7241480Smckusick 	0,	0,
7341480Smckusick 	50,	DCABRD(50),
7441480Smckusick 	75,	DCABRD(75),
7541480Smckusick 	110,	DCABRD(110),
7641480Smckusick 	134,	DCABRD(134),
7741480Smckusick 	150,	DCABRD(150),
7841480Smckusick 	200,	DCABRD(200),
7941480Smckusick 	300,	DCABRD(300),
8041480Smckusick 	600,	DCABRD(600),
8141480Smckusick 	1200,	DCABRD(1200),
8241480Smckusick 	1800,	DCABRD(1800),
8341480Smckusick 	2400,	DCABRD(2400),
8441480Smckusick 	4800,	DCABRD(4800),
8541480Smckusick 	9600,	DCABRD(9600),
8641480Smckusick 	19200,	DCABRD(19200),
8741480Smckusick 	38400,	DCABRD(38400),
8841480Smckusick 	-1,	-1
8941480Smckusick };
9041480Smckusick 
9141480Smckusick #ifdef KGDB
9256504Sbostic #include <machine/remote-sl.h>
9349130Skarels 
9450219Skarels extern dev_t kgdb_dev;
9541480Smckusick extern int kgdb_rate;
9641480Smckusick extern int kgdb_debug_init;
9741480Smckusick #endif
9841480Smckusick 
9941480Smckusick #define	UNIT(x)		minor(x)
10041480Smckusick 
10149300Shibler #ifdef DEBUG
10249300Shibler long	fifoin[17];
10349300Shibler long	fifoout[17];
10449300Shibler long	dcaintrcount[16];
10549300Shibler long	dcamintcount[16];
10649300Shibler #endif
10749300Shibler 
10841480Smckusick dcaprobe(hd)
10941480Smckusick 	register struct hp_device *hd;
11041480Smckusick {
11141480Smckusick 	register struct dcadevice *dca;
11241480Smckusick 	register int unit;
11341480Smckusick 
11441480Smckusick 	dca = (struct dcadevice *)hd->hp_addr;
11553923Shibler #ifdef hp300
11653923Shibler 	if (dca->dca_id != DCAID0 &&
11753923Shibler 	    dca->dca_id != DCAREMID0 &&
11853923Shibler 	    dca->dca_id != DCAID1 &&
11953923Shibler 	    dca->dca_id != DCAREMID1)
12041480Smckusick 		return (0);
12153923Shibler #endif
12241480Smckusick 	unit = hd->hp_unit;
12341480Smckusick 	if (unit == dcaconsole)
12441480Smckusick 		DELAY(100000);
12553923Shibler #ifdef hp300
12653923Shibler 	dca->dca_reset = 0xFF;
12741480Smckusick 	DELAY(100);
12853923Shibler #endif
12941480Smckusick 
13049300Shibler 	/* look for a NS 16550AF UART with FIFOs */
13149300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
13249300Shibler 	DELAY(100);
13349300Shibler 	if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
13449300Shibler 		dca_hasfifo |= 1 << unit;
13549300Shibler 
13653923Shibler 	dca_addr[unit] = dca;
13753923Shibler #ifdef hp300
13841480Smckusick 	hd->hp_ipl = DCAIPL(dca->dca_ic);
13941480Smckusick 	dcaisr[unit].isr_ipl = hd->hp_ipl;
14041480Smckusick 	dcaisr[unit].isr_arg = unit;
14141480Smckusick 	dcaisr[unit].isr_intr = dcaintr;
14253923Shibler 	isrlink(&dcaisr[unit]);
14353923Shibler #endif
14441480Smckusick 	dca_active |= 1 << unit;
14553923Shibler 	if (hd->hp_flags)
14653923Shibler 		dcasoftCAR |= (1 << unit);
14741480Smckusick #ifdef KGDB
14849130Skarels 	if (kgdb_dev == makedev(dcamajor, unit)) {
14941480Smckusick 		if (dcaconsole == unit)
15050219Skarels 			kgdb_dev = NODEV; /* can't debug over console port */
15141480Smckusick 		else {
15249130Skarels 			(void) dcainit(unit, kgdb_rate);
15350219Skarels 			dcaconsinit = 1;	/* don't re-init in dcaputc */
15441480Smckusick 			if (kgdb_debug_init) {
15549130Skarels 				/*
15649130Skarels 				 * Print prefix of device name,
15749130Skarels 				 * let kgdb_connect print the rest.
15849130Skarels 				 */
15949130Skarels 				printf("dca%d: ", unit);
16049130Skarels 				kgdb_connect(1);
16141480Smckusick 			} else
16241480Smckusick 				printf("dca%d: kgdb enabled\n", unit);
16341480Smckusick 		}
16441480Smckusick 	}
16541480Smckusick #endif
16653923Shibler #ifdef hp300
16741480Smckusick 	dca->dca_ic = IC_IE;
16853923Shibler #endif
16941480Smckusick 	/*
17049130Skarels 	 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
17149130Skarels 	 * Also make sure console is always "hardwired."
17241480Smckusick 	 */
17341480Smckusick 	if (unit == dcaconsole) {
17449130Skarels 		dcaconsinit = 0;
17541480Smckusick 		dcasoftCAR |= (1 << unit);
17641480Smckusick 	}
17741480Smckusick 	return (1);
17841480Smckusick }
17941480Smckusick 
18049130Skarels /* ARGSUSED */
18149130Skarels #ifdef __STDC__
18249130Skarels dcaopen(dev_t dev, int flag, int mode, struct proc *p)
18349130Skarels #else
18449130Skarels dcaopen(dev, flag, mode, p)
18541480Smckusick 	dev_t dev;
18649130Skarels 	int flag, mode;
18749130Skarels 	struct proc *p;
18849130Skarels #endif
18941480Smckusick {
19041480Smckusick 	register struct tty *tp;
19141480Smckusick 	register int unit;
19244762Skarels 	int error = 0;
19341480Smckusick 
19441480Smckusick 	unit = UNIT(dev);
19541480Smckusick 	if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
19641480Smckusick 		return (ENXIO);
19741480Smckusick 	tp = &dca_tty[unit];
19841480Smckusick 	tp->t_oproc = dcastart;
19941480Smckusick 	tp->t_param = dcaparam;
20041480Smckusick 	tp->t_dev = dev;
20141480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
20242950Smarc 		tp->t_state |= TS_WOPEN;
20341480Smckusick 		ttychars(tp);
20449130Skarels 		if (tp->t_ispeed == 0) {
20549130Skarels 			tp->t_iflag = TTYDEF_IFLAG;
20649130Skarels 			tp->t_oflag = TTYDEF_OFLAG;
20749130Skarels 			tp->t_cflag = TTYDEF_CFLAG;
20849130Skarels 			tp->t_lflag = TTYDEF_LFLAG;
20949130Skarels 			tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
21049130Skarels 		}
21141480Smckusick 		dcaparam(tp, &tp->t_termios);
21241480Smckusick 		ttsetwater(tp);
21349130Skarels 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
21441480Smckusick 		return (EBUSY);
21541480Smckusick 	(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
21641480Smckusick 	if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
21741480Smckusick 		tp->t_state |= TS_CARR_ON;
21841480Smckusick 	(void) spltty();
21944295Shibler 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
22041480Smckusick 	       (tp->t_state & TS_CARR_ON) == 0) {
22141480Smckusick 		tp->t_state |= TS_WOPEN;
22244295Shibler 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
22344295Shibler 		    ttopen, 0))
22444295Shibler 			break;
22541480Smckusick 	}
22641480Smckusick 	(void) spl0();
22744295Shibler 	if (error == 0)
22844295Shibler 		error = (*linesw[tp->t_line].l_open)(dev, tp);
22957308Shibler #ifdef hp300
23057308Shibler 	/*
23157308Shibler 	 * XXX hack to speed up unbuffered builtin port.
23257308Shibler 	 * If dca_fastservice is set, a level 5 interrupt
23357308Shibler 	 * will be directed to dcaintr first.
23457308Shibler 	 */
23557308Shibler 	if (error == 0 && unit == 0 && (dca_hasfifo & 1) == 0)
23657308Shibler 		dcafastservice = 1;
23757308Shibler #endif
23844295Shibler 	return (error);
23941480Smckusick }
24041480Smckusick 
24141480Smckusick /*ARGSUSED*/
24249750Smarc dcaclose(dev, flag, mode, p)
24341480Smckusick 	dev_t dev;
24449750Smarc 	int flag, mode;
24549750Smarc 	struct proc *p;
24641480Smckusick {
24741480Smckusick 	register struct tty *tp;
24841480Smckusick 	register struct dcadevice *dca;
24941480Smckusick 	register int unit;
25041480Smckusick 
25141480Smckusick 	unit = UNIT(dev);
25257308Shibler #ifdef hp300
25357308Shibler 	if (unit == 0)
25457308Shibler 		dcafastservice = 0;
25557308Shibler #endif
25641480Smckusick 	dca = dca_addr[unit];
25741480Smckusick 	tp = &dca_tty[unit];
25849750Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
25941480Smckusick 	dca->dca_cfcr &= ~CFCR_SBREAK;
26041480Smckusick #ifdef KGDB
26141480Smckusick 	/* do not disable interrupts if debugging */
26249130Skarels 	if (dev != kgdb_dev)
26341480Smckusick #endif
26441480Smckusick 	dca->dca_ier = 0;
26550219Skarels 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
26650219Skarels 	    (tp->t_state&TS_ISOPEN) == 0)
26750219Skarels 		(void) dcamctl(dev, 0, DMSET);
26841480Smckusick 	ttyclose(tp);
26950219Skarels 	return (0);
27041480Smckusick }
27141480Smckusick 
27241480Smckusick dcaread(dev, uio, flag)
27341480Smckusick 	dev_t dev;
27441480Smckusick 	struct uio *uio;
27541480Smckusick {
27657308Shibler 	int unit = UNIT(dev);
27757308Shibler 	register struct tty *tp = &dca_tty[unit];
27857308Shibler 	int error, of;
27941480Smckusick 
28057308Shibler 	of = dcaoflows[unit];
28157308Shibler 	error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
28257308Shibler 	/*
28357308Shibler 	 * XXX hardly a reasonable thing to do, but reporting overflows
28457308Shibler 	 * at interrupt time just exacerbates the problem.
28557308Shibler 	 */
28657308Shibler 	if (dcaoflows[unit] != of)
28757308Shibler 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
28857308Shibler 	return (error);
28941480Smckusick }
29041480Smckusick 
29141480Smckusick dcawrite(dev, uio, flag)
29241480Smckusick 	dev_t dev;
29341480Smckusick 	struct uio *uio;
29441480Smckusick {
29541480Smckusick 	int unit = UNIT(dev);
29641480Smckusick 	register struct tty *tp = &dca_tty[unit];
29753923Shibler 	extern struct tty *constty;
29841480Smckusick 
29942353Smckusick 	/*
30042353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
30142353Smckusick 	 * a serial port.  This is in case there is a display attached that
30242353Smckusick 	 * is not the console.  In that situation we don't need/want the X
30342353Smckusick 	 * server taking over the console.
30442353Smckusick 	 */
30542353Smckusick 	if (constty && unit == dcaconsole)
30642353Smckusick 		constty = NULL;
30741480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
30841480Smckusick }
30941480Smckusick 
31041480Smckusick dcaintr(unit)
31141480Smckusick 	register int unit;
31241480Smckusick {
31341480Smckusick 	register struct dcadevice *dca;
31444318Shibler 	register u_char code;
31544318Shibler 	register struct tty *tp;
31657308Shibler 	int iflowdone = 0;
31741480Smckusick 
31841480Smckusick 	dca = dca_addr[unit];
31953923Shibler #ifdef hp300
32053923Shibler 	if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
32150219Skarels 		return (0);
32253923Shibler #endif
32357308Shibler 	tp = &dca_tty[unit];
32444318Shibler 	while (1) {
32544318Shibler 		code = dca->dca_iir;
32649300Shibler #ifdef DEBUG
32749300Shibler 		dcaintrcount[code & IIR_IMASK]++;
32849300Shibler #endif
32949300Shibler 		switch (code & IIR_IMASK) {
33044318Shibler 		case IIR_NOPEND:
33144318Shibler 			return (1);
33249300Shibler 		case IIR_RXTOUT:
33344318Shibler 		case IIR_RXRDY:
33444318Shibler 			/* do time-critical read in-line */
33549300Shibler /*
33649300Shibler  * Process a received byte.  Inline for speed...
33749300Shibler  */
33844318Shibler #ifdef KGDB
33949300Shibler #define	RCVBYTE() \
34049300Shibler 			code = dca->dca_data; \
34149300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
34250219Skarels 				if (code == FRAME_END && \
34350219Skarels 				    kgdb_dev == makedev(dcamajor, unit)) \
34449300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
34549300Shibler 			} else \
34649300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
34749300Shibler #else
34849300Shibler #define	RCVBYTE() \
34949300Shibler 			code = dca->dca_data; \
35049300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
35149300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
35244318Shibler #endif
35349300Shibler 			RCVBYTE();
35449300Shibler 			if (dca_hasfifo & (1 << unit)) {
35549300Shibler #ifdef DEBUG
35649300Shibler 				register int fifocnt = 1;
35749300Shibler #endif
35849300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
35949300Shibler 					if (code == LSR_RXRDY) {
36049300Shibler 						RCVBYTE();
36149300Shibler 					} else
36249300Shibler 						dcaeint(unit, code, dca);
36349300Shibler #ifdef DEBUG
36449300Shibler 					fifocnt++;
36549300Shibler #endif
36649300Shibler 				}
36749300Shibler #ifdef DEBUG
36849300Shibler 				if (fifocnt > 16)
36949300Shibler 					fifoin[0]++;
37049300Shibler 				else
37149300Shibler 					fifoin[fifocnt]++;
37249300Shibler #endif
37349300Shibler 			}
37457308Shibler 			if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) &&
37557308Shibler 			    tp->t_rawq.c_cc > TTYHOG/2) {
37657308Shibler 				dca->dca_mcr &= ~MCR_RTS;
37757308Shibler 				iflowdone = 1;
37857308Shibler 			}
37944318Shibler 			break;
38044318Shibler 		case IIR_TXRDY:
38144318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
38244318Shibler 			if (tp->t_line)
38344318Shibler 				(*linesw[tp->t_line].l_start)(tp);
38444318Shibler 			else
38544318Shibler 				dcastart(tp);
38644318Shibler 			break;
38744318Shibler 		case IIR_RLS:
38849300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
38944318Shibler 			break;
39044318Shibler 		default:
39144318Shibler 			if (code & IIR_NOPEND)
39244318Shibler 				return (1);
39344318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
39444318Shibler 			    unit, code);
39544318Shibler 			/* fall through */
39644318Shibler 		case IIR_MLSC:
39741480Smckusick 			dcamint(unit, dca);
39844318Shibler 			break;
39944318Shibler 		}
40041480Smckusick 	}
40141480Smckusick }
40241480Smckusick 
40349300Shibler dcaeint(unit, stat, dca)
40449300Shibler 	register int unit, stat;
40541480Smckusick 	register struct dcadevice *dca;
40641480Smckusick {
40741480Smckusick 	register struct tty *tp;
40849300Shibler 	register int c;
40941480Smckusick 
41041480Smckusick 	tp = &dca_tty[unit];
41144318Shibler 	c = dca->dca_data;
41241480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
41341480Smckusick #ifdef KGDB
41441480Smckusick 		/* we don't care about parity errors */
41541480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
41649130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
41749130Skarels 			kgdb_connect(0); /* trap into kgdb */
41841480Smckusick #endif
41941480Smckusick 		return;
42041480Smckusick 	}
42141480Smckusick 	if (stat & (LSR_BI | LSR_FE))
42241480Smckusick 		c |= TTY_FE;
42341480Smckusick 	else if (stat & LSR_PE)
42441480Smckusick 		c |= TTY_PE;
42541480Smckusick 	else if (stat & LSR_OE)
42657308Shibler 		dcaoflows[unit]++;
42741480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
42841480Smckusick }
42941480Smckusick 
43041480Smckusick dcamint(unit, dca)
43141480Smckusick 	register int unit;
43241480Smckusick 	register struct dcadevice *dca;
43341480Smckusick {
43441480Smckusick 	register struct tty *tp;
43553923Shibler 	register u_char stat;
43641480Smckusick 
43741480Smckusick 	tp = &dca_tty[unit];
43841480Smckusick 	stat = dca->dca_msr;
43949300Shibler #ifdef DEBUG
44049300Shibler 	dcamintcount[stat & 0xf]++;
44149300Shibler #endif
44257308Shibler 	if ((stat & MSR_DDCD) &&
44357308Shibler 	    (dcasoftCAR & (1 << unit)) == 0) {
44441480Smckusick 		if (stat & MSR_DCD)
44544318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
44641480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
44741480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
44857308Shibler 	}
44957308Shibler 	/*
45057308Shibler 	 * CTS change.
45157308Shibler 	 * If doing HW output flow control start/stop output as appropriate.
45257308Shibler 	 */
45357308Shibler 	if ((stat & MSR_DCTS) &&
45457308Shibler 	    (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
45544318Shibler 		if (stat & MSR_CTS) {
45644318Shibler 			tp->t_state &=~ TS_TTSTOP;
45757308Shibler 			dcastart(tp);
45857308Shibler 		} else {
45944318Shibler 			tp->t_state |= TS_TTSTOP;
46057308Shibler 		}
46141480Smckusick 	}
46241480Smckusick }
46341480Smckusick 
46452421Smckusick dcaioctl(dev, cmd, data, flag, p)
46541480Smckusick 	dev_t dev;
46652421Smckusick 	int cmd;
46741480Smckusick 	caddr_t data;
46852421Smckusick 	int flag;
46952421Smckusick 	struct proc *p;
47041480Smckusick {
47141480Smckusick 	register struct tty *tp;
47241480Smckusick 	register int unit = UNIT(dev);
47341480Smckusick 	register struct dcadevice *dca;
47441480Smckusick 	register int error;
47541480Smckusick 
47641480Smckusick 	tp = &dca_tty[unit];
47752421Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
47841480Smckusick 	if (error >= 0)
47941480Smckusick 		return (error);
48041480Smckusick 	error = ttioctl(tp, cmd, data, flag);
48141480Smckusick 	if (error >= 0)
48241480Smckusick 		return (error);
48341480Smckusick 
48441480Smckusick 	dca = dca_addr[unit];
48541480Smckusick 	switch (cmd) {
48641480Smckusick 
48741480Smckusick 	case TIOCSBRK:
48841480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
48941480Smckusick 		break;
49041480Smckusick 
49141480Smckusick 	case TIOCCBRK:
49241480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
49341480Smckusick 		break;
49441480Smckusick 
49541480Smckusick 	case TIOCSDTR:
49641480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
49741480Smckusick 		break;
49841480Smckusick 
49941480Smckusick 	case TIOCCDTR:
50041480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
50141480Smckusick 		break;
50241480Smckusick 
50341480Smckusick 	case TIOCMSET:
50441480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
50541480Smckusick 		break;
50641480Smckusick 
50741480Smckusick 	case TIOCMBIS:
50841480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
50941480Smckusick 		break;
51041480Smckusick 
51141480Smckusick 	case TIOCMBIC:
51241480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
51341480Smckusick 		break;
51441480Smckusick 
51541480Smckusick 	case TIOCMGET:
51641480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
51741480Smckusick 		break;
51841480Smckusick 
51941480Smckusick 	default:
52041480Smckusick 		return (ENOTTY);
52141480Smckusick 	}
52241480Smckusick 	return (0);
52341480Smckusick }
52441480Smckusick 
52541480Smckusick dcaparam(tp, t)
52641480Smckusick 	register struct tty *tp;
52741480Smckusick 	register struct termios *t;
52841480Smckusick {
52941480Smckusick 	register struct dcadevice *dca;
53041480Smckusick 	register int cfcr, cflag = t->c_cflag;
53141480Smckusick 	int unit = UNIT(tp->t_dev);
53241480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
53341480Smckusick 
53441480Smckusick 	/* check requested parameters */
53541480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
53650219Skarels                 return (EINVAL);
53741480Smckusick         /* and copy to tty */
53841480Smckusick         tp->t_ispeed = t->c_ispeed;
53941480Smckusick         tp->t_ospeed = t->c_ospeed;
54041480Smckusick         tp->t_cflag = cflag;
54141480Smckusick 
54241480Smckusick 	dca = dca_addr[unit];
54341480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
54453923Shibler #ifdef hp700
54553923Shibler 	dca->dca_mcr |= MCR_IEN;
54653923Shibler #endif
54741480Smckusick 	if (ospeed == 0) {
54841480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
54950219Skarels 		return (0);
55041480Smckusick 	}
55141480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
55241480Smckusick 	dca->dca_data = ospeed & 0xFF;
55341480Smckusick 	dca->dca_ier = ospeed >> 8;
55441480Smckusick 	switch (cflag&CSIZE) {
55541480Smckusick 	case CS5:
55641480Smckusick 		cfcr = CFCR_5BITS; break;
55741480Smckusick 	case CS6:
55841480Smckusick 		cfcr = CFCR_6BITS; break;
55941480Smckusick 	case CS7:
56041480Smckusick 		cfcr = CFCR_7BITS; break;
56141480Smckusick 	case CS8:
56241480Smckusick 		cfcr = CFCR_8BITS; break;
56341480Smckusick 	}
56441480Smckusick 	if (cflag&PARENB) {
56541480Smckusick 		cfcr |= CFCR_PENAB;
56641480Smckusick 		if ((cflag&PARODD) == 0)
56741480Smckusick 			cfcr |= CFCR_PEVEN;
56841480Smckusick 	}
56941480Smckusick 	if (cflag&CSTOPB)
57041480Smckusick 		cfcr |= CFCR_STOPB;
57141480Smckusick 	dca->dca_cfcr = cfcr;
57249300Shibler 	if (dca_hasfifo & (1 << unit))
57349300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
57450219Skarels 	return (0);
57541480Smckusick }
57641480Smckusick 
57752389Smckusick void
57841480Smckusick dcastart(tp)
57941480Smckusick 	register struct tty *tp;
58041480Smckusick {
58141480Smckusick 	register struct dcadevice *dca;
58241480Smckusick 	int s, unit, c;
58341480Smckusick 
58441480Smckusick 	unit = UNIT(tp->t_dev);
58541480Smckusick 	dca = dca_addr[unit];
58641480Smckusick 	s = spltty();
58744318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
58841480Smckusick 		goto out;
58941480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
59041480Smckusick 		if (tp->t_state&TS_ASLEEP) {
59141480Smckusick 			tp->t_state &= ~TS_ASLEEP;
59241480Smckusick 			wakeup((caddr_t)&tp->t_outq);
59341480Smckusick 		}
59452529Storek 		selwakeup(&tp->t_wsel);
59541480Smckusick 	}
59641480Smckusick 	if (tp->t_outq.c_cc == 0)
59741480Smckusick 		goto out;
59844318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
59944318Shibler 		c = getc(&tp->t_outq);
60044318Shibler 		tp->t_state |= TS_BUSY;
60144318Shibler 		dca->dca_data = c;
60249300Shibler 		if (dca_hasfifo & (1 << unit)) {
60349300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
60449300Shibler 				dca->dca_data = getc(&tp->t_outq);
60549300Shibler #ifdef DEBUG
60649300Shibler 			if (c > 16)
60749300Shibler 				fifoout[0]++;
60849300Shibler 			else
60949300Shibler 				fifoout[c]++;
61049300Shibler #endif
61149300Shibler 		}
61244318Shibler 	}
61341480Smckusick out:
61441480Smckusick 	splx(s);
61541480Smckusick }
61641480Smckusick 
61741480Smckusick /*
61841480Smckusick  * Stop output on a line.
61941480Smckusick  */
62041480Smckusick /*ARGSUSED*/
62141480Smckusick dcastop(tp, flag)
62241480Smckusick 	register struct tty *tp;
62341480Smckusick {
62441480Smckusick 	register int s;
62541480Smckusick 
62641480Smckusick 	s = spltty();
62741480Smckusick 	if (tp->t_state & TS_BUSY) {
62841480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
62941480Smckusick 			tp->t_state |= TS_FLUSH;
63041480Smckusick 	}
63141480Smckusick 	splx(s);
63241480Smckusick }
63341480Smckusick 
63441480Smckusick dcamctl(dev, bits, how)
63541480Smckusick 	dev_t dev;
63641480Smckusick 	int bits, how;
63741480Smckusick {
63841480Smckusick 	register struct dcadevice *dca;
63941480Smckusick 	register int unit;
64041480Smckusick 	int s;
64141480Smckusick 
64241480Smckusick 	unit = UNIT(dev);
64341480Smckusick 	dca = dca_addr[unit];
64453923Shibler #ifdef hp700
64553923Shibler 	/*
64653923Shibler 	 * Always make sure MCR_IEN is set (unless setting to 0)
64753923Shibler 	 */
64853923Shibler #ifdef KGDB
64953923Shibler 	if (how == DMSET && kgdb_dev == makedev(dcamajor, unit))
65053923Shibler 		bits |= MCR_IEN;
65153923Shibler 	else
65253923Shibler #endif
65353923Shibler 	if (how == DMBIS || (how == DMSET && bits))
65453923Shibler 		bits |= MCR_IEN;
65553923Shibler 	else if (how == DMBIC)
65653923Shibler 		bits &= ~MCR_IEN;
65753923Shibler #endif
65841480Smckusick 	s = spltty();
65941480Smckusick 	switch (how) {
66041480Smckusick 
66141480Smckusick 	case DMSET:
66241480Smckusick 		dca->dca_mcr = bits;
66341480Smckusick 		break;
66441480Smckusick 
66541480Smckusick 	case DMBIS:
66641480Smckusick 		dca->dca_mcr |= bits;
66741480Smckusick 		break;
66841480Smckusick 
66941480Smckusick 	case DMBIC:
67041480Smckusick 		dca->dca_mcr &= ~bits;
67141480Smckusick 		break;
67241480Smckusick 
67341480Smckusick 	case DMGET:
67441480Smckusick 		bits = dca->dca_msr;
67541480Smckusick 		break;
67641480Smckusick 	}
67741480Smckusick 	(void) splx(s);
67850219Skarels 	return (bits);
67941480Smckusick }
68041480Smckusick 
68141480Smckusick /*
68241480Smckusick  * Following are all routines needed for DCA to act as console
68341480Smckusick  */
68456504Sbostic #include <hp/dev/cons.h>
68541480Smckusick 
68641480Smckusick dcacnprobe(cp)
68741480Smckusick 	struct consdev *cp;
68841480Smckusick {
68949300Shibler 	int unit;
69041480Smckusick 
69149130Skarels 	/* locate the major number */
69249130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
69349130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
69449130Skarels 			break;
69549130Skarels 
69641480Smckusick 	/* XXX: ick */
69741480Smckusick 	unit = CONUNIT;
69853923Shibler #ifdef hp300
69949300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
70041480Smckusick 
70141480Smckusick 	/* make sure hardware exists */
70241480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
70341480Smckusick 		cp->cn_pri = CN_DEAD;
70441480Smckusick 		return;
70541480Smckusick 	}
70653923Shibler #endif
70753923Shibler #ifdef hp700
70853923Shibler 	dca_addr[CONUNIT] = CONPORT;
70953923Shibler #endif
71041480Smckusick 
71141480Smckusick 	/* initialize required fields */
71249130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
71341480Smckusick 	cp->cn_tp = &dca_tty[unit];
71453923Shibler #ifdef hp300
71553923Shibler 	switch (dca_addr[unit]->dca_id) {
71641480Smckusick 	case DCAID0:
71741480Smckusick 	case DCAID1:
71841480Smckusick 		cp->cn_pri = CN_NORMAL;
71941480Smckusick 		break;
72041480Smckusick 	case DCAREMID0:
72141480Smckusick 	case DCAREMID1:
72241480Smckusick 		cp->cn_pri = CN_REMOTE;
72341480Smckusick 		break;
72441480Smckusick 	default:
72541480Smckusick 		cp->cn_pri = CN_DEAD;
72641480Smckusick 		break;
72741480Smckusick 	}
72853923Shibler #endif
72953923Shibler #ifdef hp700
73053923Shibler 	cp->cn_pri = CN_NORMAL;
73153923Shibler #endif
73249130Skarels 	/*
73349300Shibler 	 * If dcaconsole is initialized, raise our priority.
73449130Skarels 	 */
73549130Skarels 	if (dcaconsole == unit)
73649130Skarels 		cp->cn_pri = CN_REMOTE;
73749300Shibler #ifdef KGDB
73849130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
73949130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
74049300Shibler #endif
74141480Smckusick }
74241480Smckusick 
74341480Smckusick dcacninit(cp)
74441480Smckusick 	struct consdev *cp;
74541480Smckusick {
74641480Smckusick 	int unit = UNIT(cp->cn_dev);
74741480Smckusick 
74849130Skarels 	dcainit(unit, dcadefaultrate);
74941480Smckusick 	dcaconsole = unit;
75049130Skarels 	dcaconsinit = 1;
75141480Smckusick }
75241480Smckusick 
75349130Skarels dcainit(unit, rate)
75449130Skarels 	int unit, rate;
75541480Smckusick {
75641480Smckusick 	register struct dcadevice *dca;
75749130Skarels 	int s;
75841480Smckusick 	short stat;
75941480Smckusick 
76041480Smckusick #ifdef lint
76141480Smckusick 	stat = unit; if (stat) return;
76241480Smckusick #endif
76341480Smckusick 	dca = dca_addr[unit];
76441480Smckusick 	s = splhigh();
76553923Shibler #ifdef hp300
76653923Shibler 	dca->dca_reset = 0xFF;
76741480Smckusick 	DELAY(100);
76841480Smckusick 	dca->dca_ic = IC_IE;
76953923Shibler #endif
77041480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
77149130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
77241480Smckusick 	dca->dca_data = rate & 0xFF;
77341480Smckusick 	dca->dca_ier = rate >> 8;
77441480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
77541480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
77653923Shibler #ifdef hp700
77753923Shibler 	dca->dca_mcr |= MCR_IEN;
77853923Shibler #endif
77949300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
78053923Shibler 	DELAY(100);
78141480Smckusick 	stat = dca->dca_iir;
78241480Smckusick 	splx(s);
78341480Smckusick }
78441480Smckusick 
78541480Smckusick dcacngetc(dev)
78641480Smckusick {
78741480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
78853923Shibler 	register u_char stat;
78941480Smckusick 	int c, s;
79041480Smckusick 
79141480Smckusick #ifdef lint
79250219Skarels 	stat = dev; if (stat) return (0);
79341480Smckusick #endif
79441480Smckusick 	s = splhigh();
79541480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
79641480Smckusick 		;
79741480Smckusick 	c = dca->dca_data;
79841480Smckusick 	stat = dca->dca_iir;
79941480Smckusick 	splx(s);
80050219Skarels 	return (c);
80141480Smckusick }
80241480Smckusick 
80341480Smckusick /*
80441480Smckusick  * Console kernel output character routine.
80541480Smckusick  */
80641480Smckusick dcacnputc(dev, c)
80741480Smckusick 	dev_t dev;
80841480Smckusick 	register int c;
80941480Smckusick {
81041480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
81141480Smckusick 	register int timo;
81253923Shibler 	register u_char stat;
81341480Smckusick 	int s = splhigh();
81441480Smckusick 
81541480Smckusick #ifdef lint
81641480Smckusick 	stat = dev; if (stat) return;
81741480Smckusick #endif
81849130Skarels 	if (dcaconsinit == 0) {
81949130Skarels 		(void) dcainit(UNIT(dev), dcadefaultrate);
82049130Skarels 		dcaconsinit = 1;
82141480Smckusick 	}
82241480Smckusick 	/* wait for any pending transmission to finish */
82341480Smckusick 	timo = 50000;
82441480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
82541480Smckusick 		;
82641480Smckusick 	dca->dca_data = c;
82741480Smckusick 	/* wait for this transmission to complete */
82841480Smckusick 	timo = 1500000;
82941480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
83041480Smckusick 		;
83153923Shibler 	/*
83253923Shibler 	 * If the "normal" interface was busy transfering a character
83353923Shibler 	 * we must let our interrupt through to keep things moving.
83453923Shibler 	 * Otherwise, we clear the interrupt that we have caused.
83553923Shibler 	 */
83653923Shibler 	if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0)
83753923Shibler 		stat = dca->dca_iir;
83841480Smckusick 	splx(s);
83941480Smckusick }
84041480Smckusick #endif
841