xref: /csrg-svn/sys/hp/dev/dca.c (revision 68159)
141480Smckusick /*
263146Sbostic  * Copyright (c) 1982, 1986, 1990, 1993
363146Sbostic  *	The Regents of the University of California.  All rights reserved.
441480Smckusick  *
541480Smckusick  * %sccs.include.redist.c%
641480Smckusick  *
7*68159Scgd  *	@(#)dca.c	8.3 (Berkeley) 01/09/95
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 
dcaprobe(hd)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__
dcaopen(dev_t dev,int flag,int mode,struct proc * p)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*/
dcaclose(dev,flag,mode,p)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 
dcaread(dev,uio,flag)27241480Smckusick dcaread(dev, uio, flag)
27341480Smckusick 	dev_t dev;
27441480Smckusick 	struct uio *uio;
27565641Sbostic 	int flag;
27641480Smckusick {
27757308Shibler 	int unit = UNIT(dev);
27857308Shibler 	register struct tty *tp = &dca_tty[unit];
27957308Shibler 	int error, of;
28041480Smckusick 
28157308Shibler 	of = dcaoflows[unit];
28257308Shibler 	error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
28357308Shibler 	/*
28457308Shibler 	 * XXX hardly a reasonable thing to do, but reporting overflows
28557308Shibler 	 * at interrupt time just exacerbates the problem.
28657308Shibler 	 */
28757308Shibler 	if (dcaoflows[unit] != of)
28857308Shibler 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
28957308Shibler 	return (error);
29041480Smckusick }
29141480Smckusick 
dcawrite(dev,uio,flag)29241480Smckusick dcawrite(dev, uio, flag)
29341480Smckusick 	dev_t dev;
29441480Smckusick 	struct uio *uio;
29565641Sbostic 	int flag;
29641480Smckusick {
29741480Smckusick 	int unit = UNIT(dev);
29841480Smckusick 	register struct tty *tp = &dca_tty[unit];
29953923Shibler 	extern struct tty *constty;
30041480Smckusick 
30142353Smckusick 	/*
30242353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
30342353Smckusick 	 * a serial port.  This is in case there is a display attached that
30442353Smckusick 	 * is not the console.  In that situation we don't need/want the X
30542353Smckusick 	 * server taking over the console.
30642353Smckusick 	 */
30742353Smckusick 	if (constty && unit == dcaconsole)
30842353Smckusick 		constty = NULL;
30941480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
31041480Smckusick }
31141480Smckusick 
dcaintr(unit)31241480Smckusick dcaintr(unit)
31341480Smckusick 	register int unit;
31441480Smckusick {
31541480Smckusick 	register struct dcadevice *dca;
31644318Shibler 	register u_char code;
31744318Shibler 	register struct tty *tp;
31857308Shibler 	int iflowdone = 0;
31941480Smckusick 
32041480Smckusick 	dca = dca_addr[unit];
32153923Shibler #ifdef hp300
32253923Shibler 	if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
32350219Skarels 		return (0);
32453923Shibler #endif
32557308Shibler 	tp = &dca_tty[unit];
32644318Shibler 	while (1) {
32744318Shibler 		code = dca->dca_iir;
32849300Shibler #ifdef DEBUG
32949300Shibler 		dcaintrcount[code & IIR_IMASK]++;
33049300Shibler #endif
33149300Shibler 		switch (code & IIR_IMASK) {
33244318Shibler 		case IIR_NOPEND:
33344318Shibler 			return (1);
33449300Shibler 		case IIR_RXTOUT:
33544318Shibler 		case IIR_RXRDY:
33644318Shibler 			/* do time-critical read in-line */
33749300Shibler /*
33849300Shibler  * Process a received byte.  Inline for speed...
33949300Shibler  */
34044318Shibler #ifdef KGDB
34149300Shibler #define	RCVBYTE() \
34249300Shibler 			code = dca->dca_data; \
34349300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
34450219Skarels 				if (code == FRAME_END && \
34550219Skarels 				    kgdb_dev == makedev(dcamajor, unit)) \
34649300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
34749300Shibler 			} else \
34849300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
34949300Shibler #else
35049300Shibler #define	RCVBYTE() \
35149300Shibler 			code = dca->dca_data; \
35249300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
35349300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
35444318Shibler #endif
35549300Shibler 			RCVBYTE();
35649300Shibler 			if (dca_hasfifo & (1 << unit)) {
35749300Shibler #ifdef DEBUG
35849300Shibler 				register int fifocnt = 1;
35949300Shibler #endif
36049300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
36149300Shibler 					if (code == LSR_RXRDY) {
36249300Shibler 						RCVBYTE();
36349300Shibler 					} else
36449300Shibler 						dcaeint(unit, code, dca);
36549300Shibler #ifdef DEBUG
36649300Shibler 					fifocnt++;
36749300Shibler #endif
36849300Shibler 				}
36949300Shibler #ifdef DEBUG
37049300Shibler 				if (fifocnt > 16)
37149300Shibler 					fifoin[0]++;
37249300Shibler 				else
37349300Shibler 					fifoin[fifocnt]++;
37449300Shibler #endif
37549300Shibler 			}
37657308Shibler 			if (!iflowdone && (tp->t_cflag&CRTS_IFLOW) &&
37757308Shibler 			    tp->t_rawq.c_cc > TTYHOG/2) {
37857308Shibler 				dca->dca_mcr &= ~MCR_RTS;
37957308Shibler 				iflowdone = 1;
38057308Shibler 			}
38144318Shibler 			break;
38244318Shibler 		case IIR_TXRDY:
38344318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
38444318Shibler 			if (tp->t_line)
38544318Shibler 				(*linesw[tp->t_line].l_start)(tp);
38644318Shibler 			else
38744318Shibler 				dcastart(tp);
38844318Shibler 			break;
38944318Shibler 		case IIR_RLS:
39049300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
39144318Shibler 			break;
39244318Shibler 		default:
39344318Shibler 			if (code & IIR_NOPEND)
39444318Shibler 				return (1);
39544318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
39644318Shibler 			    unit, code);
39744318Shibler 			/* fall through */
39844318Shibler 		case IIR_MLSC:
39941480Smckusick 			dcamint(unit, dca);
40044318Shibler 			break;
40144318Shibler 		}
40241480Smckusick 	}
40341480Smckusick }
40441480Smckusick 
dcaeint(unit,stat,dca)40549300Shibler dcaeint(unit, stat, dca)
40649300Shibler 	register int unit, stat;
40741480Smckusick 	register struct dcadevice *dca;
40841480Smckusick {
40941480Smckusick 	register struct tty *tp;
41049300Shibler 	register int c;
41141480Smckusick 
41241480Smckusick 	tp = &dca_tty[unit];
41344318Shibler 	c = dca->dca_data;
41441480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
41541480Smckusick #ifdef KGDB
41641480Smckusick 		/* we don't care about parity errors */
41741480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
41849130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
41949130Skarels 			kgdb_connect(0); /* trap into kgdb */
42041480Smckusick #endif
42141480Smckusick 		return;
42241480Smckusick 	}
42341480Smckusick 	if (stat & (LSR_BI | LSR_FE))
42441480Smckusick 		c |= TTY_FE;
42541480Smckusick 	else if (stat & LSR_PE)
42641480Smckusick 		c |= TTY_PE;
42741480Smckusick 	else if (stat & LSR_OE)
42857308Shibler 		dcaoflows[unit]++;
42941480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
43041480Smckusick }
43141480Smckusick 
dcamint(unit,dca)43241480Smckusick dcamint(unit, dca)
43341480Smckusick 	register int unit;
43441480Smckusick 	register struct dcadevice *dca;
43541480Smckusick {
43641480Smckusick 	register struct tty *tp;
43753923Shibler 	register u_char stat;
43841480Smckusick 
43941480Smckusick 	tp = &dca_tty[unit];
44041480Smckusick 	stat = dca->dca_msr;
44149300Shibler #ifdef DEBUG
44249300Shibler 	dcamintcount[stat & 0xf]++;
44349300Shibler #endif
44457308Shibler 	if ((stat & MSR_DDCD) &&
44557308Shibler 	    (dcasoftCAR & (1 << unit)) == 0) {
44641480Smckusick 		if (stat & MSR_DCD)
44744318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
44841480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
44941480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
45057308Shibler 	}
45157308Shibler 	/*
45257308Shibler 	 * CTS change.
45357308Shibler 	 * If doing HW output flow control start/stop output as appropriate.
45457308Shibler 	 */
45557308Shibler 	if ((stat & MSR_DCTS) &&
45657308Shibler 	    (tp->t_state & TS_ISOPEN) && (tp->t_cflag & CCTS_OFLOW)) {
45744318Shibler 		if (stat & MSR_CTS) {
45844318Shibler 			tp->t_state &=~ TS_TTSTOP;
45957308Shibler 			dcastart(tp);
46057308Shibler 		} else {
46144318Shibler 			tp->t_state |= TS_TTSTOP;
46257308Shibler 		}
46341480Smckusick 	}
46441480Smckusick }
46541480Smckusick 
dcaioctl(dev,cmd,data,flag,p)46652421Smckusick dcaioctl(dev, cmd, data, flag, p)
46741480Smckusick 	dev_t dev;
468*68159Scgd 	u_long cmd;
46941480Smckusick 	caddr_t data;
47052421Smckusick 	int flag;
47152421Smckusick 	struct proc *p;
47241480Smckusick {
47341480Smckusick 	register struct tty *tp;
47441480Smckusick 	register int unit = UNIT(dev);
47541480Smckusick 	register struct dcadevice *dca;
47641480Smckusick 	register int error;
47741480Smckusick 
47841480Smckusick 	tp = &dca_tty[unit];
47952421Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
48041480Smckusick 	if (error >= 0)
48141480Smckusick 		return (error);
48241480Smckusick 	error = ttioctl(tp, cmd, data, flag);
48341480Smckusick 	if (error >= 0)
48441480Smckusick 		return (error);
48541480Smckusick 
48641480Smckusick 	dca = dca_addr[unit];
48741480Smckusick 	switch (cmd) {
48841480Smckusick 
48941480Smckusick 	case TIOCSBRK:
49041480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
49141480Smckusick 		break;
49241480Smckusick 
49341480Smckusick 	case TIOCCBRK:
49441480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
49541480Smckusick 		break;
49641480Smckusick 
49741480Smckusick 	case TIOCSDTR:
49841480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
49941480Smckusick 		break;
50041480Smckusick 
50141480Smckusick 	case TIOCCDTR:
50241480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
50341480Smckusick 		break;
50441480Smckusick 
50541480Smckusick 	case TIOCMSET:
50641480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
50741480Smckusick 		break;
50841480Smckusick 
50941480Smckusick 	case TIOCMBIS:
51041480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
51141480Smckusick 		break;
51241480Smckusick 
51341480Smckusick 	case TIOCMBIC:
51441480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
51541480Smckusick 		break;
51641480Smckusick 
51741480Smckusick 	case TIOCMGET:
51841480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
51941480Smckusick 		break;
52041480Smckusick 
52141480Smckusick 	default:
52241480Smckusick 		return (ENOTTY);
52341480Smckusick 	}
52441480Smckusick 	return (0);
52541480Smckusick }
52641480Smckusick 
dcaparam(tp,t)52741480Smckusick dcaparam(tp, t)
52841480Smckusick 	register struct tty *tp;
52941480Smckusick 	register struct termios *t;
53041480Smckusick {
53141480Smckusick 	register struct dcadevice *dca;
53241480Smckusick 	register int cfcr, cflag = t->c_cflag;
53341480Smckusick 	int unit = UNIT(tp->t_dev);
53441480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
53541480Smckusick 
53641480Smckusick 	/* check requested parameters */
53741480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
53850219Skarels                 return (EINVAL);
53941480Smckusick         /* and copy to tty */
54041480Smckusick         tp->t_ispeed = t->c_ispeed;
54141480Smckusick         tp->t_ospeed = t->c_ospeed;
54241480Smckusick         tp->t_cflag = cflag;
54341480Smckusick 
54441480Smckusick 	dca = dca_addr[unit];
54541480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
54653923Shibler #ifdef hp700
54753923Shibler 	dca->dca_mcr |= MCR_IEN;
54853923Shibler #endif
54941480Smckusick 	if (ospeed == 0) {
55041480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
55150219Skarels 		return (0);
55241480Smckusick 	}
55341480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
55441480Smckusick 	dca->dca_data = ospeed & 0xFF;
55541480Smckusick 	dca->dca_ier = ospeed >> 8;
55641480Smckusick 	switch (cflag&CSIZE) {
55741480Smckusick 	case CS5:
55841480Smckusick 		cfcr = CFCR_5BITS; break;
55941480Smckusick 	case CS6:
56041480Smckusick 		cfcr = CFCR_6BITS; break;
56141480Smckusick 	case CS7:
56241480Smckusick 		cfcr = CFCR_7BITS; break;
56341480Smckusick 	case CS8:
56441480Smckusick 		cfcr = CFCR_8BITS; break;
56541480Smckusick 	}
56641480Smckusick 	if (cflag&PARENB) {
56741480Smckusick 		cfcr |= CFCR_PENAB;
56841480Smckusick 		if ((cflag&PARODD) == 0)
56941480Smckusick 			cfcr |= CFCR_PEVEN;
57041480Smckusick 	}
57141480Smckusick 	if (cflag&CSTOPB)
57241480Smckusick 		cfcr |= CFCR_STOPB;
57341480Smckusick 	dca->dca_cfcr = cfcr;
57449300Shibler 	if (dca_hasfifo & (1 << unit))
57549300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
57650219Skarels 	return (0);
57741480Smckusick }
57841480Smckusick 
57952389Smckusick void
dcastart(tp)58041480Smckusick dcastart(tp)
58141480Smckusick 	register struct tty *tp;
58241480Smckusick {
58341480Smckusick 	register struct dcadevice *dca;
58441480Smckusick 	int s, unit, c;
58541480Smckusick 
58641480Smckusick 	unit = UNIT(tp->t_dev);
58741480Smckusick 	dca = dca_addr[unit];
58841480Smckusick 	s = spltty();
58944318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
59041480Smckusick 		goto out;
59141480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
59241480Smckusick 		if (tp->t_state&TS_ASLEEP) {
59341480Smckusick 			tp->t_state &= ~TS_ASLEEP;
59441480Smckusick 			wakeup((caddr_t)&tp->t_outq);
59541480Smckusick 		}
59652529Storek 		selwakeup(&tp->t_wsel);
59741480Smckusick 	}
59841480Smckusick 	if (tp->t_outq.c_cc == 0)
59941480Smckusick 		goto out;
60044318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
60144318Shibler 		c = getc(&tp->t_outq);
60244318Shibler 		tp->t_state |= TS_BUSY;
60344318Shibler 		dca->dca_data = c;
60449300Shibler 		if (dca_hasfifo & (1 << unit)) {
60549300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
60649300Shibler 				dca->dca_data = getc(&tp->t_outq);
60749300Shibler #ifdef DEBUG
60849300Shibler 			if (c > 16)
60949300Shibler 				fifoout[0]++;
61049300Shibler 			else
61149300Shibler 				fifoout[c]++;
61249300Shibler #endif
61349300Shibler 		}
61444318Shibler 	}
61541480Smckusick out:
61641480Smckusick 	splx(s);
61741480Smckusick }
61841480Smckusick 
61941480Smckusick /*
62041480Smckusick  * Stop output on a line.
62141480Smckusick  */
62241480Smckusick /*ARGSUSED*/
dcastop(tp,flag)62341480Smckusick dcastop(tp, flag)
62441480Smckusick 	register struct tty *tp;
62565641Sbostic 	int flag;
62641480Smckusick {
62741480Smckusick 	register int s;
62841480Smckusick 
62941480Smckusick 	s = spltty();
63041480Smckusick 	if (tp->t_state & TS_BUSY) {
63141480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
63241480Smckusick 			tp->t_state |= TS_FLUSH;
63341480Smckusick 	}
63441480Smckusick 	splx(s);
63541480Smckusick }
63641480Smckusick 
dcamctl(dev,bits,how)63741480Smckusick dcamctl(dev, bits, how)
63841480Smckusick 	dev_t dev;
63941480Smckusick 	int bits, how;
64041480Smckusick {
64141480Smckusick 	register struct dcadevice *dca;
64241480Smckusick 	register int unit;
64341480Smckusick 	int s;
64441480Smckusick 
64541480Smckusick 	unit = UNIT(dev);
64641480Smckusick 	dca = dca_addr[unit];
64753923Shibler #ifdef hp700
64853923Shibler 	/*
64953923Shibler 	 * Always make sure MCR_IEN is set (unless setting to 0)
65053923Shibler 	 */
65153923Shibler #ifdef KGDB
65253923Shibler 	if (how == DMSET && kgdb_dev == makedev(dcamajor, unit))
65353923Shibler 		bits |= MCR_IEN;
65453923Shibler 	else
65553923Shibler #endif
65653923Shibler 	if (how == DMBIS || (how == DMSET && bits))
65753923Shibler 		bits |= MCR_IEN;
65853923Shibler 	else if (how == DMBIC)
65953923Shibler 		bits &= ~MCR_IEN;
66053923Shibler #endif
66141480Smckusick 	s = spltty();
66241480Smckusick 	switch (how) {
66341480Smckusick 
66441480Smckusick 	case DMSET:
66541480Smckusick 		dca->dca_mcr = bits;
66641480Smckusick 		break;
66741480Smckusick 
66841480Smckusick 	case DMBIS:
66941480Smckusick 		dca->dca_mcr |= bits;
67041480Smckusick 		break;
67141480Smckusick 
67241480Smckusick 	case DMBIC:
67341480Smckusick 		dca->dca_mcr &= ~bits;
67441480Smckusick 		break;
67541480Smckusick 
67641480Smckusick 	case DMGET:
67741480Smckusick 		bits = dca->dca_msr;
67841480Smckusick 		break;
67941480Smckusick 	}
68041480Smckusick 	(void) splx(s);
68150219Skarels 	return (bits);
68241480Smckusick }
68341480Smckusick 
68441480Smckusick /*
68541480Smckusick  * Following are all routines needed for DCA to act as console
68641480Smckusick  */
68756504Sbostic #include <hp/dev/cons.h>
68841480Smckusick 
68941480Smckusick dcacnprobe(cp)
69041480Smckusick 	struct consdev *cp;
69141480Smckusick {
69249300Shibler 	int unit;
69341480Smckusick 
69449130Skarels 	/* locate the major number */
69549130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
69649130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
69749130Skarels 			break;
69849130Skarels 
69941480Smckusick 	/* XXX: ick */
70041480Smckusick 	unit = CONUNIT;
70153923Shibler #ifdef hp300
70249300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
70341480Smckusick 
70441480Smckusick 	/* make sure hardware exists */
70541480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
70641480Smckusick 		cp->cn_pri = CN_DEAD;
70741480Smckusick 		return;
70841480Smckusick 	}
70953923Shibler #endif
71053923Shibler #ifdef hp700
71153923Shibler 	dca_addr[CONUNIT] = CONPORT;
71253923Shibler #endif
71341480Smckusick 
71441480Smckusick 	/* initialize required fields */
71549130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
71641480Smckusick 	cp->cn_tp = &dca_tty[unit];
71753923Shibler #ifdef hp300
71853923Shibler 	switch (dca_addr[unit]->dca_id) {
71941480Smckusick 	case DCAID0:
72041480Smckusick 	case DCAID1:
72141480Smckusick 		cp->cn_pri = CN_NORMAL;
72241480Smckusick 		break;
72341480Smckusick 	case DCAREMID0:
72441480Smckusick 	case DCAREMID1:
72541480Smckusick 		cp->cn_pri = CN_REMOTE;
72641480Smckusick 		break;
72741480Smckusick 	default:
72841480Smckusick 		cp->cn_pri = CN_DEAD;
72941480Smckusick 		break;
73041480Smckusick 	}
73153923Shibler #endif
73253923Shibler #ifdef hp700
73353923Shibler 	cp->cn_pri = CN_NORMAL;
73453923Shibler #endif
73549130Skarels 	/*
73649300Shibler 	 * If dcaconsole is initialized, raise our priority.
73749130Skarels 	 */
73849130Skarels 	if (dcaconsole == unit)
73949130Skarels 		cp->cn_pri = CN_REMOTE;
74049300Shibler #ifdef KGDB
74149130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
74249130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
74349300Shibler #endif
74441480Smckusick }
74541480Smckusick 
74641480Smckusick dcacninit(cp)
74741480Smckusick 	struct consdev *cp;
74841480Smckusick {
74941480Smckusick 	int unit = UNIT(cp->cn_dev);
75041480Smckusick 
75149130Skarels 	dcainit(unit, dcadefaultrate);
75241480Smckusick 	dcaconsole = unit;
75349130Skarels 	dcaconsinit = 1;
75441480Smckusick }
75541480Smckusick 
dcainit(unit,rate)75649130Skarels dcainit(unit, rate)
75749130Skarels 	int unit, rate;
75841480Smckusick {
75941480Smckusick 	register struct dcadevice *dca;
76049130Skarels 	int s;
76141480Smckusick 	short stat;
76241480Smckusick 
76341480Smckusick #ifdef lint
76441480Smckusick 	stat = unit; if (stat) return;
76541480Smckusick #endif
76641480Smckusick 	dca = dca_addr[unit];
76741480Smckusick 	s = splhigh();
76853923Shibler #ifdef hp300
76953923Shibler 	dca->dca_reset = 0xFF;
77041480Smckusick 	DELAY(100);
77141480Smckusick 	dca->dca_ic = IC_IE;
77253923Shibler #endif
77341480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
77449130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
77541480Smckusick 	dca->dca_data = rate & 0xFF;
77641480Smckusick 	dca->dca_ier = rate >> 8;
77741480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
77841480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
77953923Shibler #ifdef hp700
78053923Shibler 	dca->dca_mcr |= MCR_IEN;
78153923Shibler #endif
78249300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
78353923Shibler 	DELAY(100);
78441480Smckusick 	stat = dca->dca_iir;
78541480Smckusick 	splx(s);
78641480Smckusick }
78741480Smckusick 
dcacngetc(dev)78841480Smckusick dcacngetc(dev)
78965641Sbostic 	dev_t dev;
79041480Smckusick {
79141480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
79253923Shibler 	register u_char stat;
79341480Smckusick 	int c, s;
79441480Smckusick 
79541480Smckusick #ifdef lint
79650219Skarels 	stat = dev; if (stat) return (0);
79741480Smckusick #endif
79841480Smckusick 	s = splhigh();
79941480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
80041480Smckusick 		;
80141480Smckusick 	c = dca->dca_data;
80241480Smckusick 	stat = dca->dca_iir;
80341480Smckusick 	splx(s);
80450219Skarels 	return (c);
80541480Smckusick }
80641480Smckusick 
80741480Smckusick /*
80841480Smckusick  * Console kernel output character routine.
80941480Smckusick  */
dcacnputc(dev,c)81041480Smckusick dcacnputc(dev, c)
81141480Smckusick 	dev_t dev;
81241480Smckusick 	register int c;
81341480Smckusick {
81441480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
81541480Smckusick 	register int timo;
81653923Shibler 	register u_char stat;
81741480Smckusick 	int s = splhigh();
81841480Smckusick 
81941480Smckusick #ifdef lint
82041480Smckusick 	stat = dev; if (stat) return;
82141480Smckusick #endif
82249130Skarels 	if (dcaconsinit == 0) {
82349130Skarels 		(void) dcainit(UNIT(dev), dcadefaultrate);
82449130Skarels 		dcaconsinit = 1;
82541480Smckusick 	}
82641480Smckusick 	/* wait for any pending transmission to finish */
82741480Smckusick 	timo = 50000;
82841480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
82941480Smckusick 		;
83041480Smckusick 	dca->dca_data = c;
83141480Smckusick 	/* wait for this transmission to complete */
83241480Smckusick 	timo = 1500000;
83341480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
83441480Smckusick 		;
83553923Shibler 	/*
83653923Shibler 	 * If the "normal" interface was busy transfering a character
83753923Shibler 	 * we must let our interrupt through to keep things moving.
83853923Shibler 	 * Otherwise, we clear the interrupt that we have caused.
83953923Shibler 	 */
84053923Shibler 	if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0)
84153923Shibler 		stat = dca->dca_iir;
84241480Smckusick 	splx(s);
84341480Smckusick }
84441480Smckusick #endif
845