xref: /csrg-svn/sys/hp/dev/dca.c (revision 56504)
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*56504Sbostic  *	@(#)dca.c	7.17 (Berkeley) 10/11/92
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  */
22*56504Sbostic #include <sys/param.h>
23*56504Sbostic #include <sys/systm.h>
24*56504Sbostic #include <sys/ioctl.h>
25*56504Sbostic #include <sys/proc.h>
26*56504Sbostic #include <sys/tty.h>
27*56504Sbostic #include <sys/conf.h>
28*56504Sbostic #include <sys/file.h>
29*56504Sbostic #include <sys/uio.h>
30*56504Sbostic #include <sys/kernel.h>
31*56504Sbostic #include <sys/syslog.h>
3241480Smckusick 
33*56504Sbostic #include <hp/dev/device.h>
34*56504Sbostic #include <hp/dev/dcareg.h>
3553923Shibler 
36*56504Sbostic #include <machine/cpu.h>
3753923Shibler #ifdef hp300
38*56504Sbostic #include <hp300/hp300/isr.h>
3953923Shibler #endif
4053923Shibler #ifdef hp700
41*56504Sbostic #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];
6753923Shibler #endif
6841480Smckusick 
6941480Smckusick struct speedtab dcaspeedtab[] = {
7041480Smckusick 	0,	0,
7141480Smckusick 	50,	DCABRD(50),
7241480Smckusick 	75,	DCABRD(75),
7341480Smckusick 	110,	DCABRD(110),
7441480Smckusick 	134,	DCABRD(134),
7541480Smckusick 	150,	DCABRD(150),
7641480Smckusick 	200,	DCABRD(200),
7741480Smckusick 	300,	DCABRD(300),
7841480Smckusick 	600,	DCABRD(600),
7941480Smckusick 	1200,	DCABRD(1200),
8041480Smckusick 	1800,	DCABRD(1800),
8141480Smckusick 	2400,	DCABRD(2400),
8241480Smckusick 	4800,	DCABRD(4800),
8341480Smckusick 	9600,	DCABRD(9600),
8441480Smckusick 	19200,	DCABRD(19200),
8541480Smckusick 	38400,	DCABRD(38400),
8641480Smckusick 	-1,	-1
8741480Smckusick };
8841480Smckusick 
8941480Smckusick #ifdef KGDB
90*56504Sbostic #include <machine/remote-sl.h>
9149130Skarels 
9250219Skarels extern dev_t kgdb_dev;
9341480Smckusick extern int kgdb_rate;
9441480Smckusick extern int kgdb_debug_init;
9541480Smckusick #endif
9641480Smckusick 
9741480Smckusick #define	UNIT(x)		minor(x)
9841480Smckusick 
9949300Shibler #ifdef DEBUG
10049300Shibler long	fifoin[17];
10149300Shibler long	fifoout[17];
10249300Shibler long	dcaintrcount[16];
10349300Shibler long	dcamintcount[16];
10449300Shibler #endif
10549300Shibler 
10641480Smckusick dcaprobe(hd)
10741480Smckusick 	register struct hp_device *hd;
10841480Smckusick {
10941480Smckusick 	register struct dcadevice *dca;
11041480Smckusick 	register int unit;
11141480Smckusick 
11241480Smckusick 	dca = (struct dcadevice *)hd->hp_addr;
11353923Shibler #ifdef hp300
11453923Shibler 	if (dca->dca_id != DCAID0 &&
11553923Shibler 	    dca->dca_id != DCAREMID0 &&
11653923Shibler 	    dca->dca_id != DCAID1 &&
11753923Shibler 	    dca->dca_id != DCAREMID1)
11841480Smckusick 		return (0);
11953923Shibler #endif
12041480Smckusick 	unit = hd->hp_unit;
12141480Smckusick 	if (unit == dcaconsole)
12241480Smckusick 		DELAY(100000);
12353923Shibler #ifdef hp300
12453923Shibler 	dca->dca_reset = 0xFF;
12541480Smckusick 	DELAY(100);
12653923Shibler #endif
12741480Smckusick 
12849300Shibler 	/* look for a NS 16550AF UART with FIFOs */
12949300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
13049300Shibler 	DELAY(100);
13149300Shibler 	if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
13249300Shibler 		dca_hasfifo |= 1 << unit;
13349300Shibler 
13453923Shibler 	dca_addr[unit] = dca;
13553923Shibler #ifdef hp300
13641480Smckusick 	hd->hp_ipl = DCAIPL(dca->dca_ic);
13741480Smckusick 	dcaisr[unit].isr_ipl = hd->hp_ipl;
13841480Smckusick 	dcaisr[unit].isr_arg = unit;
13941480Smckusick 	dcaisr[unit].isr_intr = dcaintr;
14053923Shibler 	isrlink(&dcaisr[unit]);
14153923Shibler #endif
14241480Smckusick 	dca_active |= 1 << unit;
14353923Shibler 	if (hd->hp_flags)
14453923Shibler 		dcasoftCAR |= (1 << unit);
14541480Smckusick #ifdef KGDB
14649130Skarels 	if (kgdb_dev == makedev(dcamajor, unit)) {
14741480Smckusick 		if (dcaconsole == unit)
14850219Skarels 			kgdb_dev = NODEV; /* can't debug over console port */
14941480Smckusick 		else {
15049130Skarels 			(void) dcainit(unit, kgdb_rate);
15150219Skarels 			dcaconsinit = 1;	/* don't re-init in dcaputc */
15241480Smckusick 			if (kgdb_debug_init) {
15349130Skarels 				/*
15449130Skarels 				 * Print prefix of device name,
15549130Skarels 				 * let kgdb_connect print the rest.
15649130Skarels 				 */
15749130Skarels 				printf("dca%d: ", unit);
15849130Skarels 				kgdb_connect(1);
15941480Smckusick 			} else
16041480Smckusick 				printf("dca%d: kgdb enabled\n", unit);
16141480Smckusick 		}
16241480Smckusick 	}
16341480Smckusick #endif
16453923Shibler #ifdef hp300
16541480Smckusick 	dca->dca_ic = IC_IE;
16653923Shibler #endif
16741480Smckusick 	/*
16849130Skarels 	 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
16949130Skarels 	 * Also make sure console is always "hardwired."
17041480Smckusick 	 */
17141480Smckusick 	if (unit == dcaconsole) {
17249130Skarels 		dcaconsinit = 0;
17341480Smckusick 		dcasoftCAR |= (1 << unit);
17441480Smckusick 	}
17541480Smckusick 	return (1);
17641480Smckusick }
17741480Smckusick 
17849130Skarels /* ARGSUSED */
17949130Skarels #ifdef __STDC__
18049130Skarels dcaopen(dev_t dev, int flag, int mode, struct proc *p)
18149130Skarels #else
18249130Skarels dcaopen(dev, flag, mode, p)
18341480Smckusick 	dev_t dev;
18449130Skarels 	int flag, mode;
18549130Skarels 	struct proc *p;
18649130Skarels #endif
18741480Smckusick {
18841480Smckusick 	register struct tty *tp;
18941480Smckusick 	register int unit;
19044762Skarels 	int error = 0;
19141480Smckusick 
19241480Smckusick 	unit = UNIT(dev);
19341480Smckusick 	if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
19441480Smckusick 		return (ENXIO);
19541480Smckusick 	tp = &dca_tty[unit];
19641480Smckusick 	tp->t_oproc = dcastart;
19741480Smckusick 	tp->t_param = dcaparam;
19841480Smckusick 	tp->t_dev = dev;
19941480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
20042950Smarc 		tp->t_state |= TS_WOPEN;
20141480Smckusick 		ttychars(tp);
20249130Skarels 		if (tp->t_ispeed == 0) {
20349130Skarels 			tp->t_iflag = TTYDEF_IFLAG;
20449130Skarels 			tp->t_oflag = TTYDEF_OFLAG;
20549130Skarels 			tp->t_cflag = TTYDEF_CFLAG;
20649130Skarels 			tp->t_lflag = TTYDEF_LFLAG;
20749130Skarels 			tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
20849130Skarels 		}
20941480Smckusick 		dcaparam(tp, &tp->t_termios);
21041480Smckusick 		ttsetwater(tp);
21149130Skarels 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
21241480Smckusick 		return (EBUSY);
21341480Smckusick 	(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
21441480Smckusick 	if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
21541480Smckusick 		tp->t_state |= TS_CARR_ON;
21641480Smckusick 	(void) spltty();
21744295Shibler 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
21841480Smckusick 	       (tp->t_state & TS_CARR_ON) == 0) {
21941480Smckusick 		tp->t_state |= TS_WOPEN;
22044295Shibler 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
22144295Shibler 		    ttopen, 0))
22244295Shibler 			break;
22341480Smckusick 	}
22441480Smckusick 	(void) spl0();
22544295Shibler 	if (error == 0)
22644295Shibler 		error = (*linesw[tp->t_line].l_open)(dev, tp);
22744295Shibler 	return (error);
22841480Smckusick }
22941480Smckusick 
23041480Smckusick /*ARGSUSED*/
23149750Smarc dcaclose(dev, flag, mode, p)
23241480Smckusick 	dev_t dev;
23349750Smarc 	int flag, mode;
23449750Smarc 	struct proc *p;
23541480Smckusick {
23641480Smckusick 	register struct tty *tp;
23741480Smckusick 	register struct dcadevice *dca;
23841480Smckusick 	register int unit;
23941480Smckusick 
24041480Smckusick 	unit = UNIT(dev);
24141480Smckusick 	dca = dca_addr[unit];
24241480Smckusick 	tp = &dca_tty[unit];
24349750Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
24441480Smckusick 	dca->dca_cfcr &= ~CFCR_SBREAK;
24541480Smckusick #ifdef KGDB
24641480Smckusick 	/* do not disable interrupts if debugging */
24749130Skarels 	if (dev != kgdb_dev)
24841480Smckusick #endif
24941480Smckusick 	dca->dca_ier = 0;
25050219Skarels 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
25150219Skarels 	    (tp->t_state&TS_ISOPEN) == 0)
25250219Skarels 		(void) dcamctl(dev, 0, DMSET);
25341480Smckusick 	ttyclose(tp);
25450219Skarels 	return (0);
25541480Smckusick }
25641480Smckusick 
25741480Smckusick dcaread(dev, uio, flag)
25841480Smckusick 	dev_t dev;
25941480Smckusick 	struct uio *uio;
26041480Smckusick {
26141480Smckusick 	register struct tty *tp = &dca_tty[UNIT(dev)];
26241480Smckusick 
26341480Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
26441480Smckusick }
26541480Smckusick 
26641480Smckusick dcawrite(dev, uio, flag)
26741480Smckusick 	dev_t dev;
26841480Smckusick 	struct uio *uio;
26941480Smckusick {
27041480Smckusick 	int unit = UNIT(dev);
27141480Smckusick 	register struct tty *tp = &dca_tty[unit];
27253923Shibler 	extern struct tty *constty;
27341480Smckusick 
27442353Smckusick 	/*
27542353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
27642353Smckusick 	 * a serial port.  This is in case there is a display attached that
27742353Smckusick 	 * is not the console.  In that situation we don't need/want the X
27842353Smckusick 	 * server taking over the console.
27942353Smckusick 	 */
28042353Smckusick 	if (constty && unit == dcaconsole)
28142353Smckusick 		constty = NULL;
28241480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
28341480Smckusick }
28441480Smckusick 
28541480Smckusick dcaintr(unit)
28641480Smckusick 	register int unit;
28741480Smckusick {
28841480Smckusick 	register struct dcadevice *dca;
28944318Shibler 	register u_char code;
29044318Shibler 	register struct tty *tp;
29141480Smckusick 
29241480Smckusick 	dca = dca_addr[unit];
29353923Shibler #ifdef hp300
29453923Shibler 	if ((dca->dca_ic & (IC_IR|IC_IE)) != (IC_IR|IC_IE))
29550219Skarels 		return (0);
29653923Shibler #endif
29744318Shibler 	while (1) {
29844318Shibler 		code = dca->dca_iir;
29949300Shibler #ifdef DEBUG
30049300Shibler 		dcaintrcount[code & IIR_IMASK]++;
30149300Shibler #endif
30249300Shibler 		switch (code & IIR_IMASK) {
30344318Shibler 		case IIR_NOPEND:
30444318Shibler 			return (1);
30549300Shibler 		case IIR_RXTOUT:
30644318Shibler 		case IIR_RXRDY:
30744318Shibler 			/* do time-critical read in-line */
30844318Shibler 			tp = &dca_tty[unit];
30949300Shibler /*
31049300Shibler  * Process a received byte.  Inline for speed...
31149300Shibler  */
31244318Shibler #ifdef KGDB
31349300Shibler #define	RCVBYTE() \
31449300Shibler 			code = dca->dca_data; \
31549300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
31650219Skarels 				if (code == FRAME_END && \
31750219Skarels 				    kgdb_dev == makedev(dcamajor, unit)) \
31849300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
31949300Shibler 			} else \
32049300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
32149300Shibler #else
32249300Shibler #define	RCVBYTE() \
32349300Shibler 			code = dca->dca_data; \
32449300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
32549300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
32644318Shibler #endif
32749300Shibler 			RCVBYTE();
32849300Shibler 			if (dca_hasfifo & (1 << unit)) {
32949300Shibler #ifdef DEBUG
33049300Shibler 				register int fifocnt = 1;
33149300Shibler #endif
33249300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
33349300Shibler 					if (code == LSR_RXRDY) {
33449300Shibler 						RCVBYTE();
33549300Shibler 					} else
33649300Shibler 						dcaeint(unit, code, dca);
33749300Shibler #ifdef DEBUG
33849300Shibler 					fifocnt++;
33949300Shibler #endif
34049300Shibler 				}
34149300Shibler #ifdef DEBUG
34249300Shibler 				if (fifocnt > 16)
34349300Shibler 					fifoin[0]++;
34449300Shibler 				else
34549300Shibler 					fifoin[fifocnt]++;
34649300Shibler #endif
34749300Shibler 			}
34844318Shibler 			break;
34944318Shibler 		case IIR_TXRDY:
35044318Shibler 			tp = &dca_tty[unit];
35144318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
35244318Shibler 			if (tp->t_line)
35344318Shibler 				(*linesw[tp->t_line].l_start)(tp);
35444318Shibler 			else
35544318Shibler 				dcastart(tp);
35644318Shibler 			break;
35744318Shibler 		case IIR_RLS:
35849300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
35944318Shibler 			break;
36044318Shibler 		default:
36144318Shibler 			if (code & IIR_NOPEND)
36244318Shibler 				return (1);
36344318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
36444318Shibler 			    unit, code);
36544318Shibler 			/* fall through */
36644318Shibler 		case IIR_MLSC:
36741480Smckusick 			dcamint(unit, dca);
36844318Shibler 			break;
36944318Shibler 		}
37041480Smckusick 	}
37141480Smckusick }
37241480Smckusick 
37349300Shibler dcaeint(unit, stat, dca)
37449300Shibler 	register int unit, stat;
37541480Smckusick 	register struct dcadevice *dca;
37641480Smckusick {
37741480Smckusick 	register struct tty *tp;
37849300Shibler 	register int c;
37941480Smckusick 
38041480Smckusick 	tp = &dca_tty[unit];
38144318Shibler 	c = dca->dca_data;
38241480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
38341480Smckusick #ifdef KGDB
38441480Smckusick 		/* we don't care about parity errors */
38541480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
38649130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
38749130Skarels 			kgdb_connect(0); /* trap into kgdb */
38841480Smckusick #endif
38941480Smckusick 		return;
39041480Smckusick 	}
39141480Smckusick 	if (stat & (LSR_BI | LSR_FE))
39241480Smckusick 		c |= TTY_FE;
39341480Smckusick 	else if (stat & LSR_PE)
39441480Smckusick 		c |= TTY_PE;
39541480Smckusick 	else if (stat & LSR_OE)
39641480Smckusick 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
39741480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
39841480Smckusick }
39941480Smckusick 
40041480Smckusick dcamint(unit, dca)
40141480Smckusick 	register int unit;
40241480Smckusick 	register struct dcadevice *dca;
40341480Smckusick {
40441480Smckusick 	register struct tty *tp;
40553923Shibler 	register u_char stat;
40641480Smckusick 
40741480Smckusick 	tp = &dca_tty[unit];
40841480Smckusick 	stat = dca->dca_msr;
40949300Shibler #ifdef DEBUG
41049300Shibler 	dcamintcount[stat & 0xf]++;
41149300Shibler #endif
41244318Shibler 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
41341480Smckusick 		if (stat & MSR_DCD)
41444318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
41541480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
41641480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
41744318Shibler 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
41844318Shibler 		   (tp->t_flags & CRTSCTS)) {
41944318Shibler 		/* the line is up and we want to do rts/cts flow control */
42044318Shibler 		if (stat & MSR_CTS) {
42144318Shibler 			tp->t_state &=~ TS_TTSTOP;
42244318Shibler 			ttstart(tp);
42344318Shibler 		} else
42444318Shibler 			tp->t_state |= TS_TTSTOP;
42541480Smckusick 	}
42641480Smckusick }
42741480Smckusick 
42852421Smckusick dcaioctl(dev, cmd, data, flag, p)
42941480Smckusick 	dev_t dev;
43052421Smckusick 	int cmd;
43141480Smckusick 	caddr_t data;
43252421Smckusick 	int flag;
43352421Smckusick 	struct proc *p;
43441480Smckusick {
43541480Smckusick 	register struct tty *tp;
43641480Smckusick 	register int unit = UNIT(dev);
43741480Smckusick 	register struct dcadevice *dca;
43841480Smckusick 	register int error;
43941480Smckusick 
44041480Smckusick 	tp = &dca_tty[unit];
44152421Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
44241480Smckusick 	if (error >= 0)
44341480Smckusick 		return (error);
44441480Smckusick 	error = ttioctl(tp, cmd, data, flag);
44541480Smckusick 	if (error >= 0)
44641480Smckusick 		return (error);
44741480Smckusick 
44841480Smckusick 	dca = dca_addr[unit];
44941480Smckusick 	switch (cmd) {
45041480Smckusick 
45141480Smckusick 	case TIOCSBRK:
45241480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
45341480Smckusick 		break;
45441480Smckusick 
45541480Smckusick 	case TIOCCBRK:
45641480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
45741480Smckusick 		break;
45841480Smckusick 
45941480Smckusick 	case TIOCSDTR:
46041480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
46141480Smckusick 		break;
46241480Smckusick 
46341480Smckusick 	case TIOCCDTR:
46441480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
46541480Smckusick 		break;
46641480Smckusick 
46741480Smckusick 	case TIOCMSET:
46841480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
46941480Smckusick 		break;
47041480Smckusick 
47141480Smckusick 	case TIOCMBIS:
47241480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
47341480Smckusick 		break;
47441480Smckusick 
47541480Smckusick 	case TIOCMBIC:
47641480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
47741480Smckusick 		break;
47841480Smckusick 
47941480Smckusick 	case TIOCMGET:
48041480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
48141480Smckusick 		break;
48241480Smckusick 
48341480Smckusick 	default:
48441480Smckusick 		return (ENOTTY);
48541480Smckusick 	}
48641480Smckusick 	return (0);
48741480Smckusick }
48841480Smckusick 
48941480Smckusick dcaparam(tp, t)
49041480Smckusick 	register struct tty *tp;
49141480Smckusick 	register struct termios *t;
49241480Smckusick {
49341480Smckusick 	register struct dcadevice *dca;
49441480Smckusick 	register int cfcr, cflag = t->c_cflag;
49541480Smckusick 	int unit = UNIT(tp->t_dev);
49641480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
49741480Smckusick 
49841480Smckusick 	/* check requested parameters */
49941480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
50050219Skarels                 return (EINVAL);
50141480Smckusick         /* and copy to tty */
50241480Smckusick         tp->t_ispeed = t->c_ispeed;
50341480Smckusick         tp->t_ospeed = t->c_ospeed;
50441480Smckusick         tp->t_cflag = cflag;
50541480Smckusick 
50641480Smckusick 	dca = dca_addr[unit];
50741480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
50853923Shibler #ifdef hp700
50953923Shibler 	dca->dca_mcr |= MCR_IEN;
51053923Shibler #endif
51141480Smckusick 	if (ospeed == 0) {
51241480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
51350219Skarels 		return (0);
51441480Smckusick 	}
51541480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
51641480Smckusick 	dca->dca_data = ospeed & 0xFF;
51741480Smckusick 	dca->dca_ier = ospeed >> 8;
51841480Smckusick 	switch (cflag&CSIZE) {
51941480Smckusick 	case CS5:
52041480Smckusick 		cfcr = CFCR_5BITS; break;
52141480Smckusick 	case CS6:
52241480Smckusick 		cfcr = CFCR_6BITS; break;
52341480Smckusick 	case CS7:
52441480Smckusick 		cfcr = CFCR_7BITS; break;
52541480Smckusick 	case CS8:
52641480Smckusick 		cfcr = CFCR_8BITS; break;
52741480Smckusick 	}
52841480Smckusick 	if (cflag&PARENB) {
52941480Smckusick 		cfcr |= CFCR_PENAB;
53041480Smckusick 		if ((cflag&PARODD) == 0)
53141480Smckusick 			cfcr |= CFCR_PEVEN;
53241480Smckusick 	}
53341480Smckusick 	if (cflag&CSTOPB)
53441480Smckusick 		cfcr |= CFCR_STOPB;
53541480Smckusick 	dca->dca_cfcr = cfcr;
53649300Shibler 	if (dca_hasfifo & (1 << unit))
53749300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
53850219Skarels 	return (0);
53941480Smckusick }
54041480Smckusick 
54152389Smckusick void
54241480Smckusick dcastart(tp)
54341480Smckusick 	register struct tty *tp;
54441480Smckusick {
54541480Smckusick 	register struct dcadevice *dca;
54641480Smckusick 	int s, unit, c;
54741480Smckusick 
54841480Smckusick 	unit = UNIT(tp->t_dev);
54941480Smckusick 	dca = dca_addr[unit];
55041480Smckusick 	s = spltty();
55144318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
55241480Smckusick 		goto out;
55341480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
55441480Smckusick 		if (tp->t_state&TS_ASLEEP) {
55541480Smckusick 			tp->t_state &= ~TS_ASLEEP;
55641480Smckusick 			wakeup((caddr_t)&tp->t_outq);
55741480Smckusick 		}
55852529Storek 		selwakeup(&tp->t_wsel);
55941480Smckusick 	}
56041480Smckusick 	if (tp->t_outq.c_cc == 0)
56141480Smckusick 		goto out;
56244318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
56344318Shibler 		c = getc(&tp->t_outq);
56444318Shibler 		tp->t_state |= TS_BUSY;
56544318Shibler 		dca->dca_data = c;
56649300Shibler 		if (dca_hasfifo & (1 << unit)) {
56749300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
56849300Shibler 				dca->dca_data = getc(&tp->t_outq);
56949300Shibler #ifdef DEBUG
57049300Shibler 			if (c > 16)
57149300Shibler 				fifoout[0]++;
57249300Shibler 			else
57349300Shibler 				fifoout[c]++;
57449300Shibler #endif
57549300Shibler 		}
57644318Shibler 	}
57741480Smckusick out:
57841480Smckusick 	splx(s);
57941480Smckusick }
58041480Smckusick 
58141480Smckusick /*
58241480Smckusick  * Stop output on a line.
58341480Smckusick  */
58441480Smckusick /*ARGSUSED*/
58541480Smckusick dcastop(tp, flag)
58641480Smckusick 	register struct tty *tp;
58741480Smckusick {
58841480Smckusick 	register int s;
58941480Smckusick 
59041480Smckusick 	s = spltty();
59141480Smckusick 	if (tp->t_state & TS_BUSY) {
59241480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
59341480Smckusick 			tp->t_state |= TS_FLUSH;
59441480Smckusick 	}
59541480Smckusick 	splx(s);
59641480Smckusick }
59741480Smckusick 
59841480Smckusick dcamctl(dev, bits, how)
59941480Smckusick 	dev_t dev;
60041480Smckusick 	int bits, how;
60141480Smckusick {
60241480Smckusick 	register struct dcadevice *dca;
60341480Smckusick 	register int unit;
60441480Smckusick 	int s;
60541480Smckusick 
60641480Smckusick 	unit = UNIT(dev);
60741480Smckusick 	dca = dca_addr[unit];
60853923Shibler #ifdef hp700
60953923Shibler 	/*
61053923Shibler 	 * Always make sure MCR_IEN is set (unless setting to 0)
61153923Shibler 	 */
61253923Shibler #ifdef KGDB
61353923Shibler 	if (how == DMSET && kgdb_dev == makedev(dcamajor, unit))
61453923Shibler 		bits |= MCR_IEN;
61553923Shibler 	else
61653923Shibler #endif
61753923Shibler 	if (how == DMBIS || (how == DMSET && bits))
61853923Shibler 		bits |= MCR_IEN;
61953923Shibler 	else if (how == DMBIC)
62053923Shibler 		bits &= ~MCR_IEN;
62153923Shibler #endif
62241480Smckusick 	s = spltty();
62341480Smckusick 	switch (how) {
62441480Smckusick 
62541480Smckusick 	case DMSET:
62641480Smckusick 		dca->dca_mcr = bits;
62741480Smckusick 		break;
62841480Smckusick 
62941480Smckusick 	case DMBIS:
63041480Smckusick 		dca->dca_mcr |= bits;
63141480Smckusick 		break;
63241480Smckusick 
63341480Smckusick 	case DMBIC:
63441480Smckusick 		dca->dca_mcr &= ~bits;
63541480Smckusick 		break;
63641480Smckusick 
63741480Smckusick 	case DMGET:
63841480Smckusick 		bits = dca->dca_msr;
63941480Smckusick 		break;
64041480Smckusick 	}
64141480Smckusick 	(void) splx(s);
64250219Skarels 	return (bits);
64341480Smckusick }
64441480Smckusick 
64541480Smckusick /*
64641480Smckusick  * Following are all routines needed for DCA to act as console
64741480Smckusick  */
648*56504Sbostic #include <hp/dev/cons.h>
64941480Smckusick 
65041480Smckusick dcacnprobe(cp)
65141480Smckusick 	struct consdev *cp;
65241480Smckusick {
65349300Shibler 	int unit;
65441480Smckusick 
65549130Skarels 	/* locate the major number */
65649130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
65749130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
65849130Skarels 			break;
65949130Skarels 
66041480Smckusick 	/* XXX: ick */
66141480Smckusick 	unit = CONUNIT;
66253923Shibler #ifdef hp300
66349300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
66441480Smckusick 
66541480Smckusick 	/* make sure hardware exists */
66641480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
66741480Smckusick 		cp->cn_pri = CN_DEAD;
66841480Smckusick 		return;
66941480Smckusick 	}
67053923Shibler #endif
67153923Shibler #ifdef hp700
67253923Shibler 	dca_addr[CONUNIT] = CONPORT;
67353923Shibler #endif
67441480Smckusick 
67541480Smckusick 	/* initialize required fields */
67649130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
67741480Smckusick 	cp->cn_tp = &dca_tty[unit];
67853923Shibler #ifdef hp300
67953923Shibler 	switch (dca_addr[unit]->dca_id) {
68041480Smckusick 	case DCAID0:
68141480Smckusick 	case DCAID1:
68241480Smckusick 		cp->cn_pri = CN_NORMAL;
68341480Smckusick 		break;
68441480Smckusick 	case DCAREMID0:
68541480Smckusick 	case DCAREMID1:
68641480Smckusick 		cp->cn_pri = CN_REMOTE;
68741480Smckusick 		break;
68841480Smckusick 	default:
68941480Smckusick 		cp->cn_pri = CN_DEAD;
69041480Smckusick 		break;
69141480Smckusick 	}
69253923Shibler #endif
69353923Shibler #ifdef hp700
69453923Shibler 	cp->cn_pri = CN_NORMAL;
69553923Shibler #endif
69649130Skarels 	/*
69749300Shibler 	 * If dcaconsole is initialized, raise our priority.
69849130Skarels 	 */
69949130Skarels 	if (dcaconsole == unit)
70049130Skarels 		cp->cn_pri = CN_REMOTE;
70149300Shibler #ifdef KGDB
70249130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
70349130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
70449300Shibler #endif
70541480Smckusick }
70641480Smckusick 
70741480Smckusick dcacninit(cp)
70841480Smckusick 	struct consdev *cp;
70941480Smckusick {
71041480Smckusick 	int unit = UNIT(cp->cn_dev);
71141480Smckusick 
71249130Skarels 	dcainit(unit, dcadefaultrate);
71341480Smckusick 	dcaconsole = unit;
71449130Skarels 	dcaconsinit = 1;
71541480Smckusick }
71641480Smckusick 
71749130Skarels dcainit(unit, rate)
71849130Skarels 	int unit, rate;
71941480Smckusick {
72041480Smckusick 	register struct dcadevice *dca;
72149130Skarels 	int s;
72241480Smckusick 	short stat;
72341480Smckusick 
72441480Smckusick #ifdef lint
72541480Smckusick 	stat = unit; if (stat) return;
72641480Smckusick #endif
72741480Smckusick 	dca = dca_addr[unit];
72841480Smckusick 	s = splhigh();
72953923Shibler #ifdef hp300
73053923Shibler 	dca->dca_reset = 0xFF;
73141480Smckusick 	DELAY(100);
73241480Smckusick 	dca->dca_ic = IC_IE;
73353923Shibler #endif
73441480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
73549130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
73641480Smckusick 	dca->dca_data = rate & 0xFF;
73741480Smckusick 	dca->dca_ier = rate >> 8;
73841480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
73941480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
74053923Shibler #ifdef hp700
74153923Shibler 	dca->dca_mcr |= MCR_IEN;
74253923Shibler #endif
74349300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
74453923Shibler 	DELAY(100);
74541480Smckusick 	stat = dca->dca_iir;
74641480Smckusick 	splx(s);
74741480Smckusick }
74841480Smckusick 
74941480Smckusick dcacngetc(dev)
75041480Smckusick {
75141480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
75253923Shibler 	register u_char stat;
75341480Smckusick 	int c, s;
75441480Smckusick 
75541480Smckusick #ifdef lint
75650219Skarels 	stat = dev; if (stat) return (0);
75741480Smckusick #endif
75841480Smckusick 	s = splhigh();
75941480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
76041480Smckusick 		;
76141480Smckusick 	c = dca->dca_data;
76241480Smckusick 	stat = dca->dca_iir;
76341480Smckusick 	splx(s);
76450219Skarels 	return (c);
76541480Smckusick }
76641480Smckusick 
76741480Smckusick /*
76841480Smckusick  * Console kernel output character routine.
76941480Smckusick  */
77041480Smckusick dcacnputc(dev, c)
77141480Smckusick 	dev_t dev;
77241480Smckusick 	register int c;
77341480Smckusick {
77441480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
77541480Smckusick 	register int timo;
77653923Shibler 	register u_char stat;
77741480Smckusick 	int s = splhigh();
77841480Smckusick 
77941480Smckusick #ifdef lint
78041480Smckusick 	stat = dev; if (stat) return;
78141480Smckusick #endif
78249130Skarels 	if (dcaconsinit == 0) {
78349130Skarels 		(void) dcainit(UNIT(dev), dcadefaultrate);
78449130Skarels 		dcaconsinit = 1;
78541480Smckusick 	}
78641480Smckusick 	/* wait for any pending transmission to finish */
78741480Smckusick 	timo = 50000;
78841480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
78941480Smckusick 		;
79041480Smckusick 	dca->dca_data = c;
79141480Smckusick 	/* wait for this transmission to complete */
79241480Smckusick 	timo = 1500000;
79341480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
79441480Smckusick 		;
79553923Shibler 	/*
79653923Shibler 	 * If the "normal" interface was busy transfering a character
79753923Shibler 	 * we must let our interrupt through to keep things moving.
79853923Shibler 	 * Otherwise, we clear the interrupt that we have caused.
79953923Shibler 	 */
80053923Shibler 	if ((dca_tty[UNIT(dev)].t_state & TS_BUSY) == 0)
80153923Shibler 		stat = dca->dca_iir;
80241480Smckusick 	splx(s);
80341480Smckusick }
80441480Smckusick #endif
805