xref: /csrg-svn/sys/hp/dev/dca.c (revision 49300)
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*49300Shibler  *	@(#)dca.c	7.10 (Berkeley) 05/07/91
841480Smckusick  */
941480Smckusick 
1041480Smckusick #include "dca.h"
1141480Smckusick #if NDCA > 0
1241480Smckusick /*
1341480Smckusick  *  98626/98644/internal serial interface
14*49300Shibler  *  uses National Semiconductor INS8250/NS16550AF UART
1541480Smckusick  */
1645788Sbostic #include "sys/param.h"
1745788Sbostic #include "sys/systm.h"
1845788Sbostic #include "sys/ioctl.h"
1945788Sbostic #include "sys/tty.h"
2049130Skarels #include "sys/proc.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 
3741480Smckusick int	dcastart(), dcaparam(), dcaintr();
3841480Smckusick int	dcasoftCAR;
3941480Smckusick int	dca_active;
40*49300Shibler int	dca_hasfifo;
4141480Smckusick int	ndca = NDCA;
4249130Skarels #ifdef DCACONSOLE
4349130Skarels int	dcaconsole = DCACONSOLE;
4449130Skarels #else
4541480Smckusick int	dcaconsole = -1;
4649130Skarels #endif
4749130Skarels int	dcaconsinit;
4841480Smckusick int	dcadefaultrate = TTYDEF_SPEED;
4949130Skarels int	dcamajor;
5041480Smckusick struct	dcadevice *dca_addr[NDCA];
5141480Smckusick struct	tty dca_tty[NDCA];
5241480Smckusick struct	isr dcaisr[NDCA];
5341480Smckusick 
5441480Smckusick struct speedtab dcaspeedtab[] = {
5541480Smckusick 	0,	0,
5641480Smckusick 	50,	DCABRD(50),
5741480Smckusick 	75,	DCABRD(75),
5841480Smckusick 	110,	DCABRD(110),
5941480Smckusick 	134,	DCABRD(134),
6041480Smckusick 	150,	DCABRD(150),
6141480Smckusick 	200,	DCABRD(200),
6241480Smckusick 	300,	DCABRD(300),
6341480Smckusick 	600,	DCABRD(600),
6441480Smckusick 	1200,	DCABRD(1200),
6541480Smckusick 	1800,	DCABRD(1800),
6641480Smckusick 	2400,	DCABRD(2400),
6741480Smckusick 	4800,	DCABRD(4800),
6841480Smckusick 	9600,	DCABRD(9600),
6941480Smckusick 	19200,	DCABRD(19200),
7041480Smckusick 	38400,	DCABRD(38400),
7141480Smckusick 	-1,	-1
7241480Smckusick };
7341480Smckusick 
7441480Smckusick extern	struct tty *constty;
7541480Smckusick #ifdef KGDB
7649130Skarels #include "machine/remote-sl.h"
7749130Skarels 
7841480Smckusick extern int kgdb_dev;
7941480Smckusick extern int kgdb_rate;
8041480Smckusick extern int kgdb_debug_init;
8141480Smckusick #endif
8241480Smckusick 
8341480Smckusick #define	UNIT(x)		minor(x)
8441480Smckusick 
85*49300Shibler #ifdef DEBUG
86*49300Shibler long	fifoin[17];
87*49300Shibler long	fifoout[17];
88*49300Shibler long	dcaintrcount[16];
89*49300Shibler long	dcamintcount[16];
90*49300Shibler #endif
91*49300Shibler 
9241480Smckusick dcaprobe(hd)
9341480Smckusick 	register struct hp_device *hd;
9441480Smckusick {
9541480Smckusick 	register struct dcadevice *dca;
9641480Smckusick 	register int unit;
9741480Smckusick 
9841480Smckusick 	dca = (struct dcadevice *)hd->hp_addr;
9941480Smckusick 	if (dca->dca_irid != DCAID0 &&
10041480Smckusick 	    dca->dca_irid != DCAREMID0 &&
10141480Smckusick 	    dca->dca_irid != DCAID1 &&
10241480Smckusick 	    dca->dca_irid != DCAREMID1)
10341480Smckusick 		return (0);
10441480Smckusick 	unit = hd->hp_unit;
10541480Smckusick 	if (unit == dcaconsole)
10641480Smckusick 		DELAY(100000);
10741480Smckusick 	dca->dca_irid = 0xFF;
10841480Smckusick 	DELAY(100);
10941480Smckusick 
110*49300Shibler 	/* look for a NS 16550AF UART with FIFOs */
111*49300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
112*49300Shibler 	DELAY(100);
113*49300Shibler 	if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
114*49300Shibler 		dca_hasfifo |= 1 << unit;
115*49300Shibler 
11641480Smckusick 	hd->hp_ipl = DCAIPL(dca->dca_ic);
11741480Smckusick 	dcaisr[unit].isr_ipl = hd->hp_ipl;
11841480Smckusick 	dcaisr[unit].isr_arg = unit;
11941480Smckusick 	dcaisr[unit].isr_intr = dcaintr;
12041480Smckusick 	dca_addr[unit] = dca;
12141480Smckusick 	dca_active |= 1 << unit;
12241480Smckusick 	dcasoftCAR = hd->hp_flags;
12341480Smckusick 	isrlink(&dcaisr[unit]);
12441480Smckusick #ifdef KGDB
12549130Skarels 	if (kgdb_dev == makedev(dcamajor, unit)) {
12641480Smckusick 		if (dcaconsole == unit)
12741480Smckusick 			kgdb_dev = -1;	/* can't debug over console port */
12841480Smckusick 		else {
12949130Skarels 			(void) dcainit(unit, kgdb_rate);
13041480Smckusick 			if (kgdb_debug_init) {
13149130Skarels 				/*
13249130Skarels 				 * Print prefix of device name,
13349130Skarels 				 * let kgdb_connect print the rest.
13449130Skarels 				 */
13549130Skarels 				printf("dca%d: ", unit);
13649130Skarels 				kgdb_connect(1);
13741480Smckusick 			} else
13841480Smckusick 				printf("dca%d: kgdb enabled\n", unit);
13941480Smckusick 		}
14041480Smckusick 	}
14141480Smckusick #endif
14241480Smckusick 	dca->dca_ic = IC_IE;
14341480Smckusick 	/*
14449130Skarels 	 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
14549130Skarels 	 * Also make sure console is always "hardwired."
14641480Smckusick 	 */
14741480Smckusick 	if (unit == dcaconsole) {
14849130Skarels 		dcaconsinit = 0;
14941480Smckusick 		dcasoftCAR |= (1 << unit);
15041480Smckusick 	}
15141480Smckusick 	return (1);
15241480Smckusick }
15341480Smckusick 
15449130Skarels /* ARGSUSED */
15549130Skarels #ifdef __STDC__
15649130Skarels dcaopen(dev_t dev, int flag, int mode, struct proc *p)
15749130Skarels #else
15849130Skarels dcaopen(dev, flag, mode, p)
15941480Smckusick 	dev_t dev;
16049130Skarels 	int flag, mode;
16149130Skarels 	struct proc *p;
16249130Skarels #endif
16341480Smckusick {
16441480Smckusick 	register struct tty *tp;
16541480Smckusick 	register int unit;
16644762Skarels 	int error = 0;
16741480Smckusick 
16841480Smckusick 	unit = UNIT(dev);
16941480Smckusick 	if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
17041480Smckusick 		return (ENXIO);
17141480Smckusick 	tp = &dca_tty[unit];
17241480Smckusick 	tp->t_oproc = dcastart;
17341480Smckusick 	tp->t_param = dcaparam;
17441480Smckusick 	tp->t_dev = dev;
17541480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
17642950Smarc 		tp->t_state |= TS_WOPEN;
17741480Smckusick 		ttychars(tp);
17849130Skarels 		if (tp->t_ispeed == 0) {
17949130Skarels 			tp->t_iflag = TTYDEF_IFLAG;
18049130Skarels 			tp->t_oflag = TTYDEF_OFLAG;
18149130Skarels 			tp->t_cflag = TTYDEF_CFLAG;
18249130Skarels 			tp->t_lflag = TTYDEF_LFLAG;
18349130Skarels 			tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
18449130Skarels 		}
18541480Smckusick 		dcaparam(tp, &tp->t_termios);
18641480Smckusick 		ttsetwater(tp);
18749130Skarels 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
18841480Smckusick 		return (EBUSY);
18941480Smckusick 	(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
19041480Smckusick 	if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
19141480Smckusick 		tp->t_state |= TS_CARR_ON;
19241480Smckusick 	(void) spltty();
19344295Shibler 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
19441480Smckusick 	       (tp->t_state & TS_CARR_ON) == 0) {
19541480Smckusick 		tp->t_state |= TS_WOPEN;
19644295Shibler 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
19744295Shibler 		    ttopen, 0))
19844295Shibler 			break;
19941480Smckusick 	}
20041480Smckusick 	(void) spl0();
20144295Shibler 	if (error == 0)
20244295Shibler 		error = (*linesw[tp->t_line].l_open)(dev, tp);
20344295Shibler 	return (error);
20441480Smckusick }
20541480Smckusick 
20641480Smckusick /*ARGSUSED*/
20741480Smckusick dcaclose(dev, flag)
20841480Smckusick 	dev_t dev;
20941480Smckusick {
21041480Smckusick 	register struct tty *tp;
21141480Smckusick 	register struct dcadevice *dca;
21241480Smckusick 	register int unit;
21341480Smckusick 
21441480Smckusick 	unit = UNIT(dev);
21541480Smckusick 	dca = dca_addr[unit];
21641480Smckusick 	tp = &dca_tty[unit];
21741480Smckusick 	(*linesw[tp->t_line].l_close)(tp);
21841480Smckusick 	dca->dca_cfcr &= ~CFCR_SBREAK;
21941480Smckusick #ifdef KGDB
22041480Smckusick 	/* do not disable interrupts if debugging */
22149130Skarels 	if (dev != kgdb_dev)
22241480Smckusick #endif
22341480Smckusick 	dca->dca_ier = 0;
22449130Skarels 	(void) dcamctl(dev, 0, DMSET);
22549130Skarels 	if (tp->t_state & TS_HUPCLS)
22649130Skarels 		(*linesw[tp->t_line].l_modem)(tp, 0);
22741480Smckusick 	ttyclose(tp);
22841480Smckusick 	return(0);
22941480Smckusick }
23041480Smckusick 
23141480Smckusick dcaread(dev, uio, flag)
23241480Smckusick 	dev_t dev;
23341480Smckusick 	struct uio *uio;
23441480Smckusick {
23541480Smckusick 	register struct tty *tp = &dca_tty[UNIT(dev)];
23641480Smckusick 
23741480Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
23841480Smckusick }
23941480Smckusick 
24041480Smckusick dcawrite(dev, uio, flag)
24141480Smckusick 	dev_t dev;
24241480Smckusick 	struct uio *uio;
24341480Smckusick {
24441480Smckusick 	int unit = UNIT(dev);
24541480Smckusick 	register struct tty *tp = &dca_tty[unit];
24641480Smckusick 
24742353Smckusick 	/*
24842353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
24942353Smckusick 	 * a serial port.  This is in case there is a display attached that
25042353Smckusick 	 * is not the console.  In that situation we don't need/want the X
25142353Smckusick 	 * server taking over the console.
25242353Smckusick 	 */
25342353Smckusick 	if (constty && unit == dcaconsole)
25442353Smckusick 		constty = NULL;
25541480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
25641480Smckusick }
25741480Smckusick 
25841480Smckusick dcaintr(unit)
25941480Smckusick 	register int unit;
26041480Smckusick {
26141480Smckusick 	register struct dcadevice *dca;
26244318Shibler 	register u_char code;
26344318Shibler 	register struct tty *tp;
26441480Smckusick 
26541480Smckusick 	dca = dca_addr[unit];
26641480Smckusick 	if ((dca->dca_ic & IC_IR) == 0)
26741480Smckusick 		return(0);
26844318Shibler 	while (1) {
26944318Shibler 		code = dca->dca_iir;
270*49300Shibler #ifdef DEBUG
271*49300Shibler 		dcaintrcount[code & IIR_IMASK]++;
272*49300Shibler #endif
273*49300Shibler 		switch (code & IIR_IMASK) {
27444318Shibler 		case IIR_NOPEND:
27544318Shibler 			return (1);
276*49300Shibler 		case IIR_RXTOUT:
27744318Shibler 		case IIR_RXRDY:
27844318Shibler 			/* do time-critical read in-line */
27944318Shibler 			tp = &dca_tty[unit];
280*49300Shibler /*
281*49300Shibler  * Process a received byte.  Inline for speed...
282*49300Shibler  */
28344318Shibler #ifdef KGDB
284*49300Shibler #define	RCVBYTE() \
285*49300Shibler 			code = dca->dca_data; \
286*49300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
287*49300Shibler 				if (kgdb_dev == makedev(dcamajor, unit) && \
288*49300Shibler 				    code == FRAME_END) \
289*49300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
290*49300Shibler 			} else \
291*49300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
292*49300Shibler #else
293*49300Shibler #define	RCVBYTE() \
294*49300Shibler 			code = dca->dca_data; \
295*49300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
296*49300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
29744318Shibler #endif
298*49300Shibler 			RCVBYTE();
299*49300Shibler 			if (dca_hasfifo & (1 << unit)) {
300*49300Shibler #ifdef DEBUG
301*49300Shibler 				register int fifocnt = 1;
302*49300Shibler #endif
303*49300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
304*49300Shibler 					if (code == LSR_RXRDY) {
305*49300Shibler 						RCVBYTE();
306*49300Shibler 					} else
307*49300Shibler 						dcaeint(unit, code, dca);
308*49300Shibler #ifdef DEBUG
309*49300Shibler 					fifocnt++;
310*49300Shibler #endif
311*49300Shibler 				}
312*49300Shibler #ifdef DEBUG
313*49300Shibler 				if (fifocnt > 16)
314*49300Shibler 					fifoin[0]++;
315*49300Shibler 				else
316*49300Shibler 					fifoin[fifocnt]++;
317*49300Shibler #endif
318*49300Shibler 			}
31944318Shibler 			break;
32044318Shibler 		case IIR_TXRDY:
32144318Shibler 			tp = &dca_tty[unit];
32244318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
32344318Shibler 			if (tp->t_line)
32444318Shibler 				(*linesw[tp->t_line].l_start)(tp);
32544318Shibler 			else
32644318Shibler 				dcastart(tp);
32744318Shibler 			break;
32844318Shibler 		case IIR_RLS:
329*49300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
33044318Shibler 			break;
33144318Shibler 		default:
33244318Shibler 			if (code & IIR_NOPEND)
33344318Shibler 				return (1);
33444318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
33544318Shibler 			    unit, code);
33644318Shibler 			/* fall through */
33744318Shibler 		case IIR_MLSC:
33841480Smckusick 			dcamint(unit, dca);
33944318Shibler 			break;
34044318Shibler 		}
34141480Smckusick 	}
34241480Smckusick }
34341480Smckusick 
344*49300Shibler dcaeint(unit, stat, dca)
345*49300Shibler 	register int unit, stat;
34641480Smckusick 	register struct dcadevice *dca;
34741480Smckusick {
34841480Smckusick 	register struct tty *tp;
349*49300Shibler 	register int c;
35041480Smckusick 
35141480Smckusick 	tp = &dca_tty[unit];
35244318Shibler 	c = dca->dca_data;
35341480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
35441480Smckusick #ifdef KGDB
35541480Smckusick 		/* we don't care about parity errors */
35641480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
35749130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
35849130Skarels 			kgdb_connect(0); /* trap into kgdb */
35941480Smckusick #endif
36041480Smckusick 		return;
36141480Smckusick 	}
36241480Smckusick 	if (stat & (LSR_BI | LSR_FE))
36341480Smckusick 		c |= TTY_FE;
36441480Smckusick 	else if (stat & LSR_PE)
36541480Smckusick 		c |= TTY_PE;
36641480Smckusick 	else if (stat & LSR_OE)
36741480Smckusick 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
36841480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
36941480Smckusick }
37041480Smckusick 
37141480Smckusick dcamint(unit, dca)
37241480Smckusick 	register int unit;
37341480Smckusick 	register struct dcadevice *dca;
37441480Smckusick {
37541480Smckusick 	register struct tty *tp;
37641480Smckusick 	register int stat;
37741480Smckusick 
37841480Smckusick 	tp = &dca_tty[unit];
37941480Smckusick 	stat = dca->dca_msr;
380*49300Shibler #ifdef DEBUG
381*49300Shibler 	dcamintcount[stat & 0xf]++;
382*49300Shibler #endif
38344318Shibler 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
38441480Smckusick 		if (stat & MSR_DCD)
38544318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
38641480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
38741480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
38844318Shibler 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
38944318Shibler 		   (tp->t_flags & CRTSCTS)) {
39044318Shibler 		/* the line is up and we want to do rts/cts flow control */
39144318Shibler 		if (stat & MSR_CTS) {
39244318Shibler 			tp->t_state &=~ TS_TTSTOP;
39344318Shibler 			ttstart(tp);
39444318Shibler 		} else
39544318Shibler 			tp->t_state |= TS_TTSTOP;
39641480Smckusick 	}
39741480Smckusick }
39841480Smckusick 
39941480Smckusick dcaioctl(dev, cmd, data, flag)
40041480Smckusick 	dev_t dev;
40141480Smckusick 	caddr_t data;
40241480Smckusick {
40341480Smckusick 	register struct tty *tp;
40441480Smckusick 	register int unit = UNIT(dev);
40541480Smckusick 	register struct dcadevice *dca;
40641480Smckusick 	register int error;
40741480Smckusick 
40841480Smckusick 	tp = &dca_tty[unit];
40941480Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
41041480Smckusick 	if (error >= 0)
41141480Smckusick 		return (error);
41241480Smckusick 	error = ttioctl(tp, cmd, data, flag);
41341480Smckusick 	if (error >= 0)
41441480Smckusick 		return (error);
41541480Smckusick 
41641480Smckusick 	dca = dca_addr[unit];
41741480Smckusick 	switch (cmd) {
41841480Smckusick 
41941480Smckusick 	case TIOCSBRK:
42041480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
42141480Smckusick 		break;
42241480Smckusick 
42341480Smckusick 	case TIOCCBRK:
42441480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
42541480Smckusick 		break;
42641480Smckusick 
42741480Smckusick 	case TIOCSDTR:
42841480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
42941480Smckusick 		break;
43041480Smckusick 
43141480Smckusick 	case TIOCCDTR:
43241480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
43341480Smckusick 		break;
43441480Smckusick 
43541480Smckusick 	case TIOCMSET:
43641480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
43741480Smckusick 		break;
43841480Smckusick 
43941480Smckusick 	case TIOCMBIS:
44041480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
44141480Smckusick 		break;
44241480Smckusick 
44341480Smckusick 	case TIOCMBIC:
44441480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
44541480Smckusick 		break;
44641480Smckusick 
44741480Smckusick 	case TIOCMGET:
44841480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
44941480Smckusick 		break;
45041480Smckusick 
45141480Smckusick 	default:
45241480Smckusick 		return (ENOTTY);
45341480Smckusick 	}
45441480Smckusick 	return (0);
45541480Smckusick }
45641480Smckusick 
45741480Smckusick dcaparam(tp, t)
45841480Smckusick 	register struct tty *tp;
45941480Smckusick 	register struct termios *t;
46041480Smckusick {
46141480Smckusick 	register struct dcadevice *dca;
46241480Smckusick 	register int cfcr, cflag = t->c_cflag;
46341480Smckusick 	int unit = UNIT(tp->t_dev);
46441480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
46541480Smckusick 
46641480Smckusick 	/* check requested parameters */
46741480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
46841480Smckusick                 return(EINVAL);
46941480Smckusick         /* and copy to tty */
47041480Smckusick         tp->t_ispeed = t->c_ispeed;
47141480Smckusick         tp->t_ospeed = t->c_ospeed;
47241480Smckusick         tp->t_cflag = cflag;
47341480Smckusick 
47441480Smckusick 	dca = dca_addr[unit];
47541480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
47641480Smckusick 	if (ospeed == 0) {
47741480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
47841480Smckusick 		return(0);
47941480Smckusick 	}
48041480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
48141480Smckusick 	dca->dca_data = ospeed & 0xFF;
48241480Smckusick 	dca->dca_ier = ospeed >> 8;
48341480Smckusick 	switch (cflag&CSIZE) {
48441480Smckusick 	case CS5:
48541480Smckusick 		cfcr = CFCR_5BITS; break;
48641480Smckusick 	case CS6:
48741480Smckusick 		cfcr = CFCR_6BITS; break;
48841480Smckusick 	case CS7:
48941480Smckusick 		cfcr = CFCR_7BITS; break;
49041480Smckusick 	case CS8:
49141480Smckusick 		cfcr = CFCR_8BITS; break;
49241480Smckusick 	}
49341480Smckusick 	if (cflag&PARENB) {
49441480Smckusick 		cfcr |= CFCR_PENAB;
49541480Smckusick 		if ((cflag&PARODD) == 0)
49641480Smckusick 			cfcr |= CFCR_PEVEN;
49741480Smckusick 	}
49841480Smckusick 	if (cflag&CSTOPB)
49941480Smckusick 		cfcr |= CFCR_STOPB;
50041480Smckusick 	dca->dca_cfcr = cfcr;
501*49300Shibler 	if (dca_hasfifo & (1 << unit))
502*49300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
50341480Smckusick 	return(0);
50441480Smckusick }
50541480Smckusick 
50641480Smckusick dcastart(tp)
50741480Smckusick 	register struct tty *tp;
50841480Smckusick {
50941480Smckusick 	register struct dcadevice *dca;
51041480Smckusick 	int s, unit, c;
51141480Smckusick 
51241480Smckusick 	unit = UNIT(tp->t_dev);
51341480Smckusick 	dca = dca_addr[unit];
51441480Smckusick 	s = spltty();
51544318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
51641480Smckusick 		goto out;
51741480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
51841480Smckusick 		if (tp->t_state&TS_ASLEEP) {
51941480Smckusick 			tp->t_state &= ~TS_ASLEEP;
52041480Smckusick 			wakeup((caddr_t)&tp->t_outq);
52141480Smckusick 		}
52241480Smckusick 		if (tp->t_wsel) {
52341480Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
52441480Smckusick 			tp->t_wsel = 0;
52541480Smckusick 			tp->t_state &= ~TS_WCOLL;
52641480Smckusick 		}
52741480Smckusick 	}
52841480Smckusick 	if (tp->t_outq.c_cc == 0)
52941480Smckusick 		goto out;
53044318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
53144318Shibler 		c = getc(&tp->t_outq);
53244318Shibler 		tp->t_state |= TS_BUSY;
53344318Shibler 		dca->dca_data = c;
534*49300Shibler 		if (dca_hasfifo & (1 << unit)) {
535*49300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
536*49300Shibler 				dca->dca_data = getc(&tp->t_outq);
537*49300Shibler #ifdef DEBUG
538*49300Shibler 			if (c > 16)
539*49300Shibler 				fifoout[0]++;
540*49300Shibler 			else
541*49300Shibler 				fifoout[c]++;
542*49300Shibler #endif
543*49300Shibler 		}
54444318Shibler 	}
54541480Smckusick out:
54641480Smckusick 	splx(s);
54741480Smckusick }
54841480Smckusick 
54941480Smckusick /*
55041480Smckusick  * Stop output on a line.
55141480Smckusick  */
55241480Smckusick /*ARGSUSED*/
55341480Smckusick dcastop(tp, flag)
55441480Smckusick 	register struct tty *tp;
55541480Smckusick {
55641480Smckusick 	register int s;
55741480Smckusick 
55841480Smckusick 	s = spltty();
55941480Smckusick 	if (tp->t_state & TS_BUSY) {
56041480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
56141480Smckusick 			tp->t_state |= TS_FLUSH;
56241480Smckusick 	}
56341480Smckusick 	splx(s);
56441480Smckusick }
56541480Smckusick 
56641480Smckusick dcamctl(dev, bits, how)
56741480Smckusick 	dev_t dev;
56841480Smckusick 	int bits, how;
56941480Smckusick {
57041480Smckusick 	register struct dcadevice *dca;
57141480Smckusick 	register int unit;
57241480Smckusick 	int s;
57341480Smckusick 
57441480Smckusick 	unit = UNIT(dev);
57541480Smckusick 	dca = dca_addr[unit];
57641480Smckusick 	s = spltty();
57741480Smckusick 	switch (how) {
57841480Smckusick 
57941480Smckusick 	case DMSET:
58041480Smckusick 		dca->dca_mcr = bits;
58141480Smckusick 		break;
58241480Smckusick 
58341480Smckusick 	case DMBIS:
58441480Smckusick 		dca->dca_mcr |= bits;
58541480Smckusick 		break;
58641480Smckusick 
58741480Smckusick 	case DMBIC:
58841480Smckusick 		dca->dca_mcr &= ~bits;
58941480Smckusick 		break;
59041480Smckusick 
59141480Smckusick 	case DMGET:
59241480Smckusick 		bits = dca->dca_msr;
59341480Smckusick 		break;
59441480Smckusick 	}
59541480Smckusick 	(void) splx(s);
59641480Smckusick 	return(bits);
59741480Smckusick }
59841480Smckusick 
59941480Smckusick /*
60041480Smckusick  * Following are all routines needed for DCA to act as console
60141480Smckusick  */
60245788Sbostic #include "../hp300/cons.h"
60341480Smckusick 
60441480Smckusick dcacnprobe(cp)
60541480Smckusick 	struct consdev *cp;
60641480Smckusick {
607*49300Shibler 	int unit;
60841480Smckusick 
60949130Skarels 	/* locate the major number */
61049130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
61149130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
61249130Skarels 			break;
61349130Skarels 
61441480Smckusick 	/* XXX: ick */
61541480Smckusick 	unit = CONUNIT;
616*49300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
61741480Smckusick 
61841480Smckusick 	/* make sure hardware exists */
61941480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
62041480Smckusick 		cp->cn_pri = CN_DEAD;
62141480Smckusick 		return;
62241480Smckusick 	}
62341480Smckusick 
62441480Smckusick 	/* initialize required fields */
62549130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
62641480Smckusick 	cp->cn_tp = &dca_tty[unit];
62741480Smckusick 	switch (dca_addr[unit]->dca_irid) {
62841480Smckusick 	case DCAID0:
62941480Smckusick 	case DCAID1:
63041480Smckusick 		cp->cn_pri = CN_NORMAL;
63141480Smckusick 		break;
63241480Smckusick 	case DCAREMID0:
63341480Smckusick 	case DCAREMID1:
63441480Smckusick 		cp->cn_pri = CN_REMOTE;
63541480Smckusick 		break;
63641480Smckusick 	default:
63741480Smckusick 		cp->cn_pri = CN_DEAD;
63841480Smckusick 		break;
63941480Smckusick 	}
64049130Skarels 	/*
641*49300Shibler 	 * If dcaconsole is initialized, raise our priority.
64249130Skarels 	 */
64349130Skarels 	if (dcaconsole == unit)
64449130Skarels 		cp->cn_pri = CN_REMOTE;
645*49300Shibler #ifdef KGDB
64649130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
64749130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
648*49300Shibler #endif
64941480Smckusick }
65041480Smckusick 
65141480Smckusick dcacninit(cp)
65241480Smckusick 	struct consdev *cp;
65341480Smckusick {
65441480Smckusick 	int unit = UNIT(cp->cn_dev);
65541480Smckusick 
65649130Skarels 	dcainit(unit, dcadefaultrate);
65741480Smckusick 	dcaconsole = unit;
65849130Skarels 	dcaconsinit = 1;
65941480Smckusick }
66041480Smckusick 
66149130Skarels dcainit(unit, rate)
66249130Skarels 	int unit, rate;
66341480Smckusick {
66441480Smckusick 	register struct dcadevice *dca;
66549130Skarels 	int s;
66641480Smckusick 	short stat;
66741480Smckusick 
66841480Smckusick #ifdef lint
66941480Smckusick 	stat = unit; if (stat) return;
67041480Smckusick #endif
67141480Smckusick 	dca = dca_addr[unit];
67241480Smckusick 	s = splhigh();
67341480Smckusick 	dca->dca_irid = 0xFF;
67441480Smckusick 	DELAY(100);
67541480Smckusick 	dca->dca_ic = IC_IE;
67641480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
67749130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
67841480Smckusick 	dca->dca_data = rate & 0xFF;
67941480Smckusick 	dca->dca_ier = rate >> 8;
68041480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
68141480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
682*49300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
68341480Smckusick 	stat = dca->dca_iir;
68441480Smckusick 	splx(s);
68541480Smckusick }
68641480Smckusick 
68741480Smckusick dcacngetc(dev)
68841480Smckusick {
68941480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
69041480Smckusick 	short stat;
69141480Smckusick 	int c, s;
69241480Smckusick 
69341480Smckusick #ifdef lint
69441480Smckusick 	stat = dev; if (stat) return(0);
69541480Smckusick #endif
69641480Smckusick 	s = splhigh();
69741480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
69841480Smckusick 		;
69941480Smckusick 	c = dca->dca_data;
70041480Smckusick 	stat = dca->dca_iir;
70141480Smckusick 	splx(s);
70241480Smckusick 	return(c);
70341480Smckusick }
70441480Smckusick 
70541480Smckusick /*
70641480Smckusick  * Console kernel output character routine.
70741480Smckusick  */
70841480Smckusick dcacnputc(dev, c)
70941480Smckusick 	dev_t dev;
71041480Smckusick 	register int c;
71141480Smckusick {
71241480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
71341480Smckusick 	register int timo;
71441480Smckusick 	short stat;
71541480Smckusick 	int s = splhigh();
71641480Smckusick 
71741480Smckusick #ifdef lint
71841480Smckusick 	stat = dev; if (stat) return;
71941480Smckusick #endif
72049130Skarels #ifdef KGDB
72149130Skarels 	if (dev != kgdb_dev)
72249130Skarels #endif
72349130Skarels 	if (dcaconsinit == 0) {
72449130Skarels 		(void) dcainit(UNIT(dev), dcadefaultrate);
72549130Skarels 		dcaconsinit = 1;
72641480Smckusick 	}
72741480Smckusick 	/* wait for any pending transmission to finish */
72841480Smckusick 	timo = 50000;
72941480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
73041480Smckusick 		;
73141480Smckusick 	dca->dca_data = c;
73241480Smckusick 	/* wait for this transmission to complete */
73341480Smckusick 	timo = 1500000;
73441480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
73541480Smckusick 		;
73641480Smckusick 	/* clear any interrupts generated by this transmission */
73741480Smckusick 	stat = dca->dca_iir;
73841480Smckusick 	splx(s);
73941480Smckusick }
74041480Smckusick #endif
741