xref: /csrg-svn/sys/hp/dev/dca.c (revision 52529)
141480Smckusick /*
241480Smckusick  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
341480Smckusick  * All rights reserved.
441480Smckusick  *
541480Smckusick  * %sccs.include.redist.c%
641480Smckusick  *
7*52529Storek  *	@(#)dca.c	7.15 (Berkeley) 02/15/92
841480Smckusick  */
941480Smckusick 
1041480Smckusick #include "dca.h"
1141480Smckusick #if NDCA > 0
1241480Smckusick /*
1341480Smckusick  *  98626/98644/internal serial interface
1449300Shibler  *  uses National Semiconductor INS8250/NS16550AF UART
1541480Smckusick  */
1645788Sbostic #include "sys/param.h"
1745788Sbostic #include "sys/systm.h"
1845788Sbostic #include "sys/ioctl.h"
19*52529Storek #include "sys/proc.h"
2045788Sbostic #include "sys/tty.h"
2145788Sbostic #include "sys/conf.h"
2245788Sbostic #include "sys/file.h"
2345788Sbostic #include "sys/uio.h"
2445788Sbostic #include "sys/kernel.h"
2545788Sbostic #include "sys/syslog.h"
2641480Smckusick 
2741480Smckusick #include "device.h"
2841480Smckusick #include "dcareg.h"
2949130Skarels #include "machine/cpu.h"
3045788Sbostic #include "../hp300/isr.h"
3141480Smckusick 
3241480Smckusick int	dcaprobe();
3341480Smckusick struct	driver dcadriver = {
3441480Smckusick 	dcaprobe, "dca",
3541480Smckusick };
3641480Smckusick 
3752389Smckusick void	dcastart();
3852389Smckusick int	dcaparam(), dcaintr();
3941480Smckusick int	dcasoftCAR;
4041480Smckusick int	dca_active;
4149300Shibler int	dca_hasfifo;
4241480Smckusick int	ndca = NDCA;
4349130Skarels #ifdef DCACONSOLE
4449130Skarels int	dcaconsole = DCACONSOLE;
4549130Skarels #else
4641480Smckusick int	dcaconsole = -1;
4749130Skarels #endif
4849130Skarels int	dcaconsinit;
4941480Smckusick int	dcadefaultrate = TTYDEF_SPEED;
5049130Skarels int	dcamajor;
5141480Smckusick struct	dcadevice *dca_addr[NDCA];
5241480Smckusick struct	tty dca_tty[NDCA];
5341480Smckusick struct	isr dcaisr[NDCA];
5441480Smckusick 
5541480Smckusick struct speedtab dcaspeedtab[] = {
5641480Smckusick 	0,	0,
5741480Smckusick 	50,	DCABRD(50),
5841480Smckusick 	75,	DCABRD(75),
5941480Smckusick 	110,	DCABRD(110),
6041480Smckusick 	134,	DCABRD(134),
6141480Smckusick 	150,	DCABRD(150),
6241480Smckusick 	200,	DCABRD(200),
6341480Smckusick 	300,	DCABRD(300),
6441480Smckusick 	600,	DCABRD(600),
6541480Smckusick 	1200,	DCABRD(1200),
6641480Smckusick 	1800,	DCABRD(1800),
6741480Smckusick 	2400,	DCABRD(2400),
6841480Smckusick 	4800,	DCABRD(4800),
6941480Smckusick 	9600,	DCABRD(9600),
7041480Smckusick 	19200,	DCABRD(19200),
7141480Smckusick 	38400,	DCABRD(38400),
7241480Smckusick 	-1,	-1
7341480Smckusick };
7441480Smckusick 
7541480Smckusick extern	struct tty *constty;
7641480Smckusick #ifdef KGDB
7749130Skarels #include "machine/remote-sl.h"
7849130Skarels 
7950219Skarels extern dev_t kgdb_dev;
8041480Smckusick extern int kgdb_rate;
8141480Smckusick extern int kgdb_debug_init;
8241480Smckusick #endif
8341480Smckusick 
8441480Smckusick #define	UNIT(x)		minor(x)
8541480Smckusick 
8649300Shibler #ifdef DEBUG
8749300Shibler long	fifoin[17];
8849300Shibler long	fifoout[17];
8949300Shibler long	dcaintrcount[16];
9049300Shibler long	dcamintcount[16];
9149300Shibler #endif
9249300Shibler 
9341480Smckusick dcaprobe(hd)
9441480Smckusick 	register struct hp_device *hd;
9541480Smckusick {
9641480Smckusick 	register struct dcadevice *dca;
9741480Smckusick 	register int unit;
9841480Smckusick 
9941480Smckusick 	dca = (struct dcadevice *)hd->hp_addr;
10041480Smckusick 	if (dca->dca_irid != DCAID0 &&
10141480Smckusick 	    dca->dca_irid != DCAREMID0 &&
10241480Smckusick 	    dca->dca_irid != DCAID1 &&
10341480Smckusick 	    dca->dca_irid != DCAREMID1)
10441480Smckusick 		return (0);
10541480Smckusick 	unit = hd->hp_unit;
10641480Smckusick 	if (unit == dcaconsole)
10741480Smckusick 		DELAY(100000);
10841480Smckusick 	dca->dca_irid = 0xFF;
10941480Smckusick 	DELAY(100);
11041480Smckusick 
11149300Shibler 	/* look for a NS 16550AF UART with FIFOs */
11249300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
11349300Shibler 	DELAY(100);
11449300Shibler 	if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
11549300Shibler 		dca_hasfifo |= 1 << unit;
11649300Shibler 
11741480Smckusick 	hd->hp_ipl = DCAIPL(dca->dca_ic);
11841480Smckusick 	dcaisr[unit].isr_ipl = hd->hp_ipl;
11941480Smckusick 	dcaisr[unit].isr_arg = unit;
12041480Smckusick 	dcaisr[unit].isr_intr = dcaintr;
12141480Smckusick 	dca_addr[unit] = dca;
12241480Smckusick 	dca_active |= 1 << unit;
12341480Smckusick 	dcasoftCAR = hd->hp_flags;
12441480Smckusick 	isrlink(&dcaisr[unit]);
12541480Smckusick #ifdef KGDB
12649130Skarels 	if (kgdb_dev == makedev(dcamajor, unit)) {
12741480Smckusick 		if (dcaconsole == unit)
12850219Skarels 			kgdb_dev = NODEV; /* can't debug over console port */
12941480Smckusick 		else {
13049130Skarels 			(void) dcainit(unit, kgdb_rate);
13150219Skarels 			dcaconsinit = 1;	/* don't re-init in dcaputc */
13241480Smckusick 			if (kgdb_debug_init) {
13349130Skarels 				/*
13449130Skarels 				 * Print prefix of device name,
13549130Skarels 				 * let kgdb_connect print the rest.
13649130Skarels 				 */
13749130Skarels 				printf("dca%d: ", unit);
13849130Skarels 				kgdb_connect(1);
13941480Smckusick 			} else
14041480Smckusick 				printf("dca%d: kgdb enabled\n", unit);
14141480Smckusick 		}
14241480Smckusick 	}
14341480Smckusick #endif
14441480Smckusick 	dca->dca_ic = IC_IE;
14541480Smckusick 	/*
14649130Skarels 	 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
14749130Skarels 	 * Also make sure console is always "hardwired."
14841480Smckusick 	 */
14941480Smckusick 	if (unit == dcaconsole) {
15049130Skarels 		dcaconsinit = 0;
15141480Smckusick 		dcasoftCAR |= (1 << unit);
15241480Smckusick 	}
15341480Smckusick 	return (1);
15441480Smckusick }
15541480Smckusick 
15649130Skarels /* ARGSUSED */
15749130Skarels #ifdef __STDC__
15849130Skarels dcaopen(dev_t dev, int flag, int mode, struct proc *p)
15949130Skarels #else
16049130Skarels dcaopen(dev, flag, mode, p)
16141480Smckusick 	dev_t dev;
16249130Skarels 	int flag, mode;
16349130Skarels 	struct proc *p;
16449130Skarels #endif
16541480Smckusick {
16641480Smckusick 	register struct tty *tp;
16741480Smckusick 	register int unit;
16844762Skarels 	int error = 0;
16941480Smckusick 
17041480Smckusick 	unit = UNIT(dev);
17141480Smckusick 	if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
17241480Smckusick 		return (ENXIO);
17341480Smckusick 	tp = &dca_tty[unit];
17441480Smckusick 	tp->t_oproc = dcastart;
17541480Smckusick 	tp->t_param = dcaparam;
17641480Smckusick 	tp->t_dev = dev;
17741480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
17842950Smarc 		tp->t_state |= TS_WOPEN;
17941480Smckusick 		ttychars(tp);
18049130Skarels 		if (tp->t_ispeed == 0) {
18149130Skarels 			tp->t_iflag = TTYDEF_IFLAG;
18249130Skarels 			tp->t_oflag = TTYDEF_OFLAG;
18349130Skarels 			tp->t_cflag = TTYDEF_CFLAG;
18449130Skarels 			tp->t_lflag = TTYDEF_LFLAG;
18549130Skarels 			tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
18649130Skarels 		}
18741480Smckusick 		dcaparam(tp, &tp->t_termios);
18841480Smckusick 		ttsetwater(tp);
18949130Skarels 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
19041480Smckusick 		return (EBUSY);
19141480Smckusick 	(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
19241480Smckusick 	if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
19341480Smckusick 		tp->t_state |= TS_CARR_ON;
19441480Smckusick 	(void) spltty();
19544295Shibler 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
19641480Smckusick 	       (tp->t_state & TS_CARR_ON) == 0) {
19741480Smckusick 		tp->t_state |= TS_WOPEN;
19844295Shibler 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
19944295Shibler 		    ttopen, 0))
20044295Shibler 			break;
20141480Smckusick 	}
20241480Smckusick 	(void) spl0();
20344295Shibler 	if (error == 0)
20444295Shibler 		error = (*linesw[tp->t_line].l_open)(dev, tp);
20544295Shibler 	return (error);
20641480Smckusick }
20741480Smckusick 
20841480Smckusick /*ARGSUSED*/
20949750Smarc dcaclose(dev, flag, mode, p)
21041480Smckusick 	dev_t dev;
21149750Smarc 	int flag, mode;
21249750Smarc 	struct proc *p;
21341480Smckusick {
21441480Smckusick 	register struct tty *tp;
21541480Smckusick 	register struct dcadevice *dca;
21641480Smckusick 	register int unit;
21741480Smckusick 
21841480Smckusick 	unit = UNIT(dev);
21941480Smckusick 	dca = dca_addr[unit];
22041480Smckusick 	tp = &dca_tty[unit];
22149750Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
22241480Smckusick 	dca->dca_cfcr &= ~CFCR_SBREAK;
22341480Smckusick #ifdef KGDB
22441480Smckusick 	/* do not disable interrupts if debugging */
22549130Skarels 	if (dev != kgdb_dev)
22641480Smckusick #endif
22741480Smckusick 	dca->dca_ier = 0;
22850219Skarels 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
22950219Skarels 	    (tp->t_state&TS_ISOPEN) == 0)
23050219Skarels 		(void) dcamctl(dev, 0, DMSET);
23141480Smckusick 	ttyclose(tp);
23250219Skarels 	return (0);
23341480Smckusick }
23441480Smckusick 
23541480Smckusick dcaread(dev, uio, flag)
23641480Smckusick 	dev_t dev;
23741480Smckusick 	struct uio *uio;
23841480Smckusick {
23941480Smckusick 	register struct tty *tp = &dca_tty[UNIT(dev)];
24041480Smckusick 
24141480Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
24241480Smckusick }
24341480Smckusick 
24441480Smckusick dcawrite(dev, uio, flag)
24541480Smckusick 	dev_t dev;
24641480Smckusick 	struct uio *uio;
24741480Smckusick {
24841480Smckusick 	int unit = UNIT(dev);
24941480Smckusick 	register struct tty *tp = &dca_tty[unit];
25041480Smckusick 
25142353Smckusick 	/*
25242353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
25342353Smckusick 	 * a serial port.  This is in case there is a display attached that
25442353Smckusick 	 * is not the console.  In that situation we don't need/want the X
25542353Smckusick 	 * server taking over the console.
25642353Smckusick 	 */
25742353Smckusick 	if (constty && unit == dcaconsole)
25842353Smckusick 		constty = NULL;
25941480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
26041480Smckusick }
26141480Smckusick 
26241480Smckusick dcaintr(unit)
26341480Smckusick 	register int unit;
26441480Smckusick {
26541480Smckusick 	register struct dcadevice *dca;
26644318Shibler 	register u_char code;
26744318Shibler 	register struct tty *tp;
26841480Smckusick 
26941480Smckusick 	dca = dca_addr[unit];
27041480Smckusick 	if ((dca->dca_ic & IC_IR) == 0)
27150219Skarels 		return (0);
27244318Shibler 	while (1) {
27344318Shibler 		code = dca->dca_iir;
27449300Shibler #ifdef DEBUG
27549300Shibler 		dcaintrcount[code & IIR_IMASK]++;
27649300Shibler #endif
27749300Shibler 		switch (code & IIR_IMASK) {
27844318Shibler 		case IIR_NOPEND:
27944318Shibler 			return (1);
28049300Shibler 		case IIR_RXTOUT:
28144318Shibler 		case IIR_RXRDY:
28244318Shibler 			/* do time-critical read in-line */
28344318Shibler 			tp = &dca_tty[unit];
28449300Shibler /*
28549300Shibler  * Process a received byte.  Inline for speed...
28649300Shibler  */
28744318Shibler #ifdef KGDB
28849300Shibler #define	RCVBYTE() \
28949300Shibler 			code = dca->dca_data; \
29049300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
29150219Skarels 				if (code == FRAME_END && \
29250219Skarels 				    kgdb_dev == makedev(dcamajor, unit)) \
29349300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
29449300Shibler 			} else \
29549300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
29649300Shibler #else
29749300Shibler #define	RCVBYTE() \
29849300Shibler 			code = dca->dca_data; \
29949300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
30049300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
30144318Shibler #endif
30249300Shibler 			RCVBYTE();
30349300Shibler 			if (dca_hasfifo & (1 << unit)) {
30449300Shibler #ifdef DEBUG
30549300Shibler 				register int fifocnt = 1;
30649300Shibler #endif
30749300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
30849300Shibler 					if (code == LSR_RXRDY) {
30949300Shibler 						RCVBYTE();
31049300Shibler 					} else
31149300Shibler 						dcaeint(unit, code, dca);
31249300Shibler #ifdef DEBUG
31349300Shibler 					fifocnt++;
31449300Shibler #endif
31549300Shibler 				}
31649300Shibler #ifdef DEBUG
31749300Shibler 				if (fifocnt > 16)
31849300Shibler 					fifoin[0]++;
31949300Shibler 				else
32049300Shibler 					fifoin[fifocnt]++;
32149300Shibler #endif
32249300Shibler 			}
32344318Shibler 			break;
32444318Shibler 		case IIR_TXRDY:
32544318Shibler 			tp = &dca_tty[unit];
32644318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
32744318Shibler 			if (tp->t_line)
32844318Shibler 				(*linesw[tp->t_line].l_start)(tp);
32944318Shibler 			else
33044318Shibler 				dcastart(tp);
33144318Shibler 			break;
33244318Shibler 		case IIR_RLS:
33349300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
33444318Shibler 			break;
33544318Shibler 		default:
33644318Shibler 			if (code & IIR_NOPEND)
33744318Shibler 				return (1);
33844318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
33944318Shibler 			    unit, code);
34044318Shibler 			/* fall through */
34144318Shibler 		case IIR_MLSC:
34241480Smckusick 			dcamint(unit, dca);
34344318Shibler 			break;
34444318Shibler 		}
34541480Smckusick 	}
34641480Smckusick }
34741480Smckusick 
34849300Shibler dcaeint(unit, stat, dca)
34949300Shibler 	register int unit, stat;
35041480Smckusick 	register struct dcadevice *dca;
35141480Smckusick {
35241480Smckusick 	register struct tty *tp;
35349300Shibler 	register int c;
35441480Smckusick 
35541480Smckusick 	tp = &dca_tty[unit];
35644318Shibler 	c = dca->dca_data;
35741480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
35841480Smckusick #ifdef KGDB
35941480Smckusick 		/* we don't care about parity errors */
36041480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
36149130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
36249130Skarels 			kgdb_connect(0); /* trap into kgdb */
36341480Smckusick #endif
36441480Smckusick 		return;
36541480Smckusick 	}
36641480Smckusick 	if (stat & (LSR_BI | LSR_FE))
36741480Smckusick 		c |= TTY_FE;
36841480Smckusick 	else if (stat & LSR_PE)
36941480Smckusick 		c |= TTY_PE;
37041480Smckusick 	else if (stat & LSR_OE)
37141480Smckusick 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
37241480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
37341480Smckusick }
37441480Smckusick 
37541480Smckusick dcamint(unit, dca)
37641480Smckusick 	register int unit;
37741480Smckusick 	register struct dcadevice *dca;
37841480Smckusick {
37941480Smckusick 	register struct tty *tp;
38041480Smckusick 	register int stat;
38141480Smckusick 
38241480Smckusick 	tp = &dca_tty[unit];
38341480Smckusick 	stat = dca->dca_msr;
38449300Shibler #ifdef DEBUG
38549300Shibler 	dcamintcount[stat & 0xf]++;
38649300Shibler #endif
38744318Shibler 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
38841480Smckusick 		if (stat & MSR_DCD)
38944318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
39041480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
39141480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
39244318Shibler 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
39344318Shibler 		   (tp->t_flags & CRTSCTS)) {
39444318Shibler 		/* the line is up and we want to do rts/cts flow control */
39544318Shibler 		if (stat & MSR_CTS) {
39644318Shibler 			tp->t_state &=~ TS_TTSTOP;
39744318Shibler 			ttstart(tp);
39844318Shibler 		} else
39944318Shibler 			tp->t_state |= TS_TTSTOP;
40041480Smckusick 	}
40141480Smckusick }
40241480Smckusick 
40352421Smckusick dcaioctl(dev, cmd, data, flag, p)
40441480Smckusick 	dev_t dev;
40552421Smckusick 	int cmd;
40641480Smckusick 	caddr_t data;
40752421Smckusick 	int flag;
40852421Smckusick 	struct proc *p;
40941480Smckusick {
41041480Smckusick 	register struct tty *tp;
41141480Smckusick 	register int unit = UNIT(dev);
41241480Smckusick 	register struct dcadevice *dca;
41341480Smckusick 	register int error;
41441480Smckusick 
41541480Smckusick 	tp = &dca_tty[unit];
41652421Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
41741480Smckusick 	if (error >= 0)
41841480Smckusick 		return (error);
41941480Smckusick 	error = ttioctl(tp, cmd, data, flag);
42041480Smckusick 	if (error >= 0)
42141480Smckusick 		return (error);
42241480Smckusick 
42341480Smckusick 	dca = dca_addr[unit];
42441480Smckusick 	switch (cmd) {
42541480Smckusick 
42641480Smckusick 	case TIOCSBRK:
42741480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
42841480Smckusick 		break;
42941480Smckusick 
43041480Smckusick 	case TIOCCBRK:
43141480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
43241480Smckusick 		break;
43341480Smckusick 
43441480Smckusick 	case TIOCSDTR:
43541480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
43641480Smckusick 		break;
43741480Smckusick 
43841480Smckusick 	case TIOCCDTR:
43941480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
44041480Smckusick 		break;
44141480Smckusick 
44241480Smckusick 	case TIOCMSET:
44341480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
44441480Smckusick 		break;
44541480Smckusick 
44641480Smckusick 	case TIOCMBIS:
44741480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
44841480Smckusick 		break;
44941480Smckusick 
45041480Smckusick 	case TIOCMBIC:
45141480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
45241480Smckusick 		break;
45341480Smckusick 
45441480Smckusick 	case TIOCMGET:
45541480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
45641480Smckusick 		break;
45741480Smckusick 
45841480Smckusick 	default:
45941480Smckusick 		return (ENOTTY);
46041480Smckusick 	}
46141480Smckusick 	return (0);
46241480Smckusick }
46341480Smckusick 
46441480Smckusick dcaparam(tp, t)
46541480Smckusick 	register struct tty *tp;
46641480Smckusick 	register struct termios *t;
46741480Smckusick {
46841480Smckusick 	register struct dcadevice *dca;
46941480Smckusick 	register int cfcr, cflag = t->c_cflag;
47041480Smckusick 	int unit = UNIT(tp->t_dev);
47141480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
47241480Smckusick 
47341480Smckusick 	/* check requested parameters */
47441480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
47550219Skarels                 return (EINVAL);
47641480Smckusick         /* and copy to tty */
47741480Smckusick         tp->t_ispeed = t->c_ispeed;
47841480Smckusick         tp->t_ospeed = t->c_ospeed;
47941480Smckusick         tp->t_cflag = cflag;
48041480Smckusick 
48141480Smckusick 	dca = dca_addr[unit];
48241480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
48341480Smckusick 	if (ospeed == 0) {
48441480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
48550219Skarels 		return (0);
48641480Smckusick 	}
48741480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
48841480Smckusick 	dca->dca_data = ospeed & 0xFF;
48941480Smckusick 	dca->dca_ier = ospeed >> 8;
49041480Smckusick 	switch (cflag&CSIZE) {
49141480Smckusick 	case CS5:
49241480Smckusick 		cfcr = CFCR_5BITS; break;
49341480Smckusick 	case CS6:
49441480Smckusick 		cfcr = CFCR_6BITS; break;
49541480Smckusick 	case CS7:
49641480Smckusick 		cfcr = CFCR_7BITS; break;
49741480Smckusick 	case CS8:
49841480Smckusick 		cfcr = CFCR_8BITS; break;
49941480Smckusick 	}
50041480Smckusick 	if (cflag&PARENB) {
50141480Smckusick 		cfcr |= CFCR_PENAB;
50241480Smckusick 		if ((cflag&PARODD) == 0)
50341480Smckusick 			cfcr |= CFCR_PEVEN;
50441480Smckusick 	}
50541480Smckusick 	if (cflag&CSTOPB)
50641480Smckusick 		cfcr |= CFCR_STOPB;
50741480Smckusick 	dca->dca_cfcr = cfcr;
50849300Shibler 	if (dca_hasfifo & (1 << unit))
50949300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
51050219Skarels 	return (0);
51141480Smckusick }
51241480Smckusick 
51352389Smckusick void
51441480Smckusick dcastart(tp)
51541480Smckusick 	register struct tty *tp;
51641480Smckusick {
51741480Smckusick 	register struct dcadevice *dca;
51841480Smckusick 	int s, unit, c;
51941480Smckusick 
52041480Smckusick 	unit = UNIT(tp->t_dev);
52141480Smckusick 	dca = dca_addr[unit];
52241480Smckusick 	s = spltty();
52344318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
52441480Smckusick 		goto out;
52541480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
52641480Smckusick 		if (tp->t_state&TS_ASLEEP) {
52741480Smckusick 			tp->t_state &= ~TS_ASLEEP;
52841480Smckusick 			wakeup((caddr_t)&tp->t_outq);
52941480Smckusick 		}
530*52529Storek 		selwakeup(&tp->t_wsel);
53141480Smckusick 	}
53241480Smckusick 	if (tp->t_outq.c_cc == 0)
53341480Smckusick 		goto out;
53444318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
53544318Shibler 		c = getc(&tp->t_outq);
53644318Shibler 		tp->t_state |= TS_BUSY;
53744318Shibler 		dca->dca_data = c;
53849300Shibler 		if (dca_hasfifo & (1 << unit)) {
53949300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
54049300Shibler 				dca->dca_data = getc(&tp->t_outq);
54149300Shibler #ifdef DEBUG
54249300Shibler 			if (c > 16)
54349300Shibler 				fifoout[0]++;
54449300Shibler 			else
54549300Shibler 				fifoout[c]++;
54649300Shibler #endif
54749300Shibler 		}
54844318Shibler 	}
54941480Smckusick out:
55041480Smckusick 	splx(s);
55141480Smckusick }
55241480Smckusick 
55341480Smckusick /*
55441480Smckusick  * Stop output on a line.
55541480Smckusick  */
55641480Smckusick /*ARGSUSED*/
55741480Smckusick dcastop(tp, flag)
55841480Smckusick 	register struct tty *tp;
55941480Smckusick {
56041480Smckusick 	register int s;
56141480Smckusick 
56241480Smckusick 	s = spltty();
56341480Smckusick 	if (tp->t_state & TS_BUSY) {
56441480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
56541480Smckusick 			tp->t_state |= TS_FLUSH;
56641480Smckusick 	}
56741480Smckusick 	splx(s);
56841480Smckusick }
56941480Smckusick 
57041480Smckusick dcamctl(dev, bits, how)
57141480Smckusick 	dev_t dev;
57241480Smckusick 	int bits, how;
57341480Smckusick {
57441480Smckusick 	register struct dcadevice *dca;
57541480Smckusick 	register int unit;
57641480Smckusick 	int s;
57741480Smckusick 
57841480Smckusick 	unit = UNIT(dev);
57941480Smckusick 	dca = dca_addr[unit];
58041480Smckusick 	s = spltty();
58141480Smckusick 	switch (how) {
58241480Smckusick 
58341480Smckusick 	case DMSET:
58441480Smckusick 		dca->dca_mcr = bits;
58541480Smckusick 		break;
58641480Smckusick 
58741480Smckusick 	case DMBIS:
58841480Smckusick 		dca->dca_mcr |= bits;
58941480Smckusick 		break;
59041480Smckusick 
59141480Smckusick 	case DMBIC:
59241480Smckusick 		dca->dca_mcr &= ~bits;
59341480Smckusick 		break;
59441480Smckusick 
59541480Smckusick 	case DMGET:
59641480Smckusick 		bits = dca->dca_msr;
59741480Smckusick 		break;
59841480Smckusick 	}
59941480Smckusick 	(void) splx(s);
60050219Skarels 	return (bits);
60141480Smckusick }
60241480Smckusick 
60341480Smckusick /*
60441480Smckusick  * Following are all routines needed for DCA to act as console
60541480Smckusick  */
60645788Sbostic #include "../hp300/cons.h"
60741480Smckusick 
60841480Smckusick dcacnprobe(cp)
60941480Smckusick 	struct consdev *cp;
61041480Smckusick {
61149300Shibler 	int unit;
61241480Smckusick 
61349130Skarels 	/* locate the major number */
61449130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
61549130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
61649130Skarels 			break;
61749130Skarels 
61841480Smckusick 	/* XXX: ick */
61941480Smckusick 	unit = CONUNIT;
62049300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
62141480Smckusick 
62241480Smckusick 	/* make sure hardware exists */
62341480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
62441480Smckusick 		cp->cn_pri = CN_DEAD;
62541480Smckusick 		return;
62641480Smckusick 	}
62741480Smckusick 
62841480Smckusick 	/* initialize required fields */
62949130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
63041480Smckusick 	cp->cn_tp = &dca_tty[unit];
63141480Smckusick 	switch (dca_addr[unit]->dca_irid) {
63241480Smckusick 	case DCAID0:
63341480Smckusick 	case DCAID1:
63441480Smckusick 		cp->cn_pri = CN_NORMAL;
63541480Smckusick 		break;
63641480Smckusick 	case DCAREMID0:
63741480Smckusick 	case DCAREMID1:
63841480Smckusick 		cp->cn_pri = CN_REMOTE;
63941480Smckusick 		break;
64041480Smckusick 	default:
64141480Smckusick 		cp->cn_pri = CN_DEAD;
64241480Smckusick 		break;
64341480Smckusick 	}
64449130Skarels 	/*
64549300Shibler 	 * If dcaconsole is initialized, raise our priority.
64649130Skarels 	 */
64749130Skarels 	if (dcaconsole == unit)
64849130Skarels 		cp->cn_pri = CN_REMOTE;
64949300Shibler #ifdef KGDB
65049130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
65149130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
65249300Shibler #endif
65341480Smckusick }
65441480Smckusick 
65541480Smckusick dcacninit(cp)
65641480Smckusick 	struct consdev *cp;
65741480Smckusick {
65841480Smckusick 	int unit = UNIT(cp->cn_dev);
65941480Smckusick 
66049130Skarels 	dcainit(unit, dcadefaultrate);
66141480Smckusick 	dcaconsole = unit;
66249130Skarels 	dcaconsinit = 1;
66341480Smckusick }
66441480Smckusick 
66549130Skarels dcainit(unit, rate)
66649130Skarels 	int unit, rate;
66741480Smckusick {
66841480Smckusick 	register struct dcadevice *dca;
66949130Skarels 	int s;
67041480Smckusick 	short stat;
67141480Smckusick 
67241480Smckusick #ifdef lint
67341480Smckusick 	stat = unit; if (stat) return;
67441480Smckusick #endif
67541480Smckusick 	dca = dca_addr[unit];
67641480Smckusick 	s = splhigh();
67741480Smckusick 	dca->dca_irid = 0xFF;
67841480Smckusick 	DELAY(100);
67941480Smckusick 	dca->dca_ic = IC_IE;
68041480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
68149130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
68241480Smckusick 	dca->dca_data = rate & 0xFF;
68341480Smckusick 	dca->dca_ier = rate >> 8;
68441480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
68541480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
68649300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
68741480Smckusick 	stat = dca->dca_iir;
68841480Smckusick 	splx(s);
68941480Smckusick }
69041480Smckusick 
69141480Smckusick dcacngetc(dev)
69241480Smckusick {
69341480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
69441480Smckusick 	short stat;
69541480Smckusick 	int c, s;
69641480Smckusick 
69741480Smckusick #ifdef lint
69850219Skarels 	stat = dev; if (stat) return (0);
69941480Smckusick #endif
70041480Smckusick 	s = splhigh();
70141480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
70241480Smckusick 		;
70341480Smckusick 	c = dca->dca_data;
70441480Smckusick 	stat = dca->dca_iir;
70541480Smckusick 	splx(s);
70650219Skarels 	return (c);
70741480Smckusick }
70841480Smckusick 
70941480Smckusick /*
71041480Smckusick  * Console kernel output character routine.
71141480Smckusick  */
71241480Smckusick dcacnputc(dev, c)
71341480Smckusick 	dev_t dev;
71441480Smckusick 	register int c;
71541480Smckusick {
71641480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
71741480Smckusick 	register int timo;
71841480Smckusick 	short stat;
71941480Smckusick 	int s = splhigh();
72041480Smckusick 
72141480Smckusick #ifdef lint
72241480Smckusick 	stat = dev; if (stat) return;
72341480Smckusick #endif
72449130Skarels 	if (dcaconsinit == 0) {
72549130Skarels 		(void) dcainit(UNIT(dev), dcadefaultrate);
72649130Skarels 		dcaconsinit = 1;
72741480Smckusick 	}
72841480Smckusick 	/* wait for any pending transmission to finish */
72941480Smckusick 	timo = 50000;
73041480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
73141480Smckusick 		;
73241480Smckusick 	dca->dca_data = c;
73341480Smckusick 	/* wait for this transmission to complete */
73441480Smckusick 	timo = 1500000;
73541480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
73641480Smckusick 		;
73741480Smckusick 	/* clear any interrupts generated by this transmission */
73841480Smckusick 	stat = dca->dca_iir;
73941480Smckusick 	splx(s);
74041480Smckusick }
74141480Smckusick #endif
742