xref: /csrg-svn/sys/hp/dev/dca.c (revision 50219)
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*50219Skarels  *	@(#)dca.c	7.12 (Berkeley) 06/27/91
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"
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;
4049300Shibler 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 
78*50219Skarels extern dev_t kgdb_dev;
7941480Smckusick extern int kgdb_rate;
8041480Smckusick extern int kgdb_debug_init;
8141480Smckusick #endif
8241480Smckusick 
8341480Smckusick #define	UNIT(x)		minor(x)
8441480Smckusick 
8549300Shibler #ifdef DEBUG
8649300Shibler long	fifoin[17];
8749300Shibler long	fifoout[17];
8849300Shibler long	dcaintrcount[16];
8949300Shibler long	dcamintcount[16];
9049300Shibler #endif
9149300Shibler 
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 
11049300Shibler 	/* look for a NS 16550AF UART with FIFOs */
11149300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
11249300Shibler 	DELAY(100);
11349300Shibler 	if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
11449300Shibler 		dca_hasfifo |= 1 << unit;
11549300Shibler 
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)
127*50219Skarels 			kgdb_dev = NODEV; /* can't debug over console port */
12841480Smckusick 		else {
12949130Skarels 			(void) dcainit(unit, kgdb_rate);
130*50219Skarels 			dcaconsinit = 1;	/* don't re-init in dcaputc */
13141480Smckusick 			if (kgdb_debug_init) {
13249130Skarels 				/*
13349130Skarels 				 * Print prefix of device name,
13449130Skarels 				 * let kgdb_connect print the rest.
13549130Skarels 				 */
13649130Skarels 				printf("dca%d: ", unit);
13749130Skarels 				kgdb_connect(1);
13841480Smckusick 			} else
13941480Smckusick 				printf("dca%d: kgdb enabled\n", unit);
14041480Smckusick 		}
14141480Smckusick 	}
14241480Smckusick #endif
14341480Smckusick 	dca->dca_ic = IC_IE;
14441480Smckusick 	/*
14549130Skarels 	 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
14649130Skarels 	 * Also make sure console is always "hardwired."
14741480Smckusick 	 */
14841480Smckusick 	if (unit == dcaconsole) {
14949130Skarels 		dcaconsinit = 0;
15041480Smckusick 		dcasoftCAR |= (1 << unit);
15141480Smckusick 	}
15241480Smckusick 	return (1);
15341480Smckusick }
15441480Smckusick 
15549130Skarels /* ARGSUSED */
15649130Skarels #ifdef __STDC__
15749130Skarels dcaopen(dev_t dev, int flag, int mode, struct proc *p)
15849130Skarels #else
15949130Skarels dcaopen(dev, flag, mode, p)
16041480Smckusick 	dev_t dev;
16149130Skarels 	int flag, mode;
16249130Skarels 	struct proc *p;
16349130Skarels #endif
16441480Smckusick {
16541480Smckusick 	register struct tty *tp;
16641480Smckusick 	register int unit;
16744762Skarels 	int error = 0;
16841480Smckusick 
16941480Smckusick 	unit = UNIT(dev);
17041480Smckusick 	if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
17141480Smckusick 		return (ENXIO);
17241480Smckusick 	tp = &dca_tty[unit];
17341480Smckusick 	tp->t_oproc = dcastart;
17441480Smckusick 	tp->t_param = dcaparam;
17541480Smckusick 	tp->t_dev = dev;
17641480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
17742950Smarc 		tp->t_state |= TS_WOPEN;
17841480Smckusick 		ttychars(tp);
17949130Skarels 		if (tp->t_ispeed == 0) {
18049130Skarels 			tp->t_iflag = TTYDEF_IFLAG;
18149130Skarels 			tp->t_oflag = TTYDEF_OFLAG;
18249130Skarels 			tp->t_cflag = TTYDEF_CFLAG;
18349130Skarels 			tp->t_lflag = TTYDEF_LFLAG;
18449130Skarels 			tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
18549130Skarels 		}
18641480Smckusick 		dcaparam(tp, &tp->t_termios);
18741480Smckusick 		ttsetwater(tp);
18849130Skarels 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
18941480Smckusick 		return (EBUSY);
19041480Smckusick 	(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
19141480Smckusick 	if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
19241480Smckusick 		tp->t_state |= TS_CARR_ON;
19341480Smckusick 	(void) spltty();
19444295Shibler 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
19541480Smckusick 	       (tp->t_state & TS_CARR_ON) == 0) {
19641480Smckusick 		tp->t_state |= TS_WOPEN;
19744295Shibler 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
19844295Shibler 		    ttopen, 0))
19944295Shibler 			break;
20041480Smckusick 	}
20141480Smckusick 	(void) spl0();
20244295Shibler 	if (error == 0)
20344295Shibler 		error = (*linesw[tp->t_line].l_open)(dev, tp);
20444295Shibler 	return (error);
20541480Smckusick }
20641480Smckusick 
20741480Smckusick /*ARGSUSED*/
20849750Smarc dcaclose(dev, flag, mode, p)
20941480Smckusick 	dev_t dev;
21049750Smarc 	int flag, mode;
21149750Smarc 	struct proc *p;
21241480Smckusick {
21341480Smckusick 	register struct tty *tp;
21441480Smckusick 	register struct dcadevice *dca;
21541480Smckusick 	register int unit;
21641480Smckusick 
21741480Smckusick 	unit = UNIT(dev);
21841480Smckusick 	dca = dca_addr[unit];
21941480Smckusick 	tp = &dca_tty[unit];
22049750Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
22141480Smckusick 	dca->dca_cfcr &= ~CFCR_SBREAK;
22241480Smckusick #ifdef KGDB
22341480Smckusick 	/* do not disable interrupts if debugging */
22449130Skarels 	if (dev != kgdb_dev)
22541480Smckusick #endif
22641480Smckusick 	dca->dca_ier = 0;
227*50219Skarels 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
228*50219Skarels 	    (tp->t_state&TS_ISOPEN) == 0)
229*50219Skarels 		(void) dcamctl(dev, 0, DMSET);
23041480Smckusick 	ttyclose(tp);
231*50219Skarels 	return (0);
23241480Smckusick }
23341480Smckusick 
23441480Smckusick dcaread(dev, uio, flag)
23541480Smckusick 	dev_t dev;
23641480Smckusick 	struct uio *uio;
23741480Smckusick {
23841480Smckusick 	register struct tty *tp = &dca_tty[UNIT(dev)];
23941480Smckusick 
24041480Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
24141480Smckusick }
24241480Smckusick 
24341480Smckusick dcawrite(dev, uio, flag)
24441480Smckusick 	dev_t dev;
24541480Smckusick 	struct uio *uio;
24641480Smckusick {
24741480Smckusick 	int unit = UNIT(dev);
24841480Smckusick 	register struct tty *tp = &dca_tty[unit];
24941480Smckusick 
25042353Smckusick 	/*
25142353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
25242353Smckusick 	 * a serial port.  This is in case there is a display attached that
25342353Smckusick 	 * is not the console.  In that situation we don't need/want the X
25442353Smckusick 	 * server taking over the console.
25542353Smckusick 	 */
25642353Smckusick 	if (constty && unit == dcaconsole)
25742353Smckusick 		constty = NULL;
25841480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
25941480Smckusick }
26041480Smckusick 
26141480Smckusick dcaintr(unit)
26241480Smckusick 	register int unit;
26341480Smckusick {
26441480Smckusick 	register struct dcadevice *dca;
26544318Shibler 	register u_char code;
26644318Shibler 	register struct tty *tp;
26741480Smckusick 
26841480Smckusick 	dca = dca_addr[unit];
26941480Smckusick 	if ((dca->dca_ic & IC_IR) == 0)
270*50219Skarels 		return (0);
27144318Shibler 	while (1) {
27244318Shibler 		code = dca->dca_iir;
27349300Shibler #ifdef DEBUG
27449300Shibler 		dcaintrcount[code & IIR_IMASK]++;
27549300Shibler #endif
27649300Shibler 		switch (code & IIR_IMASK) {
27744318Shibler 		case IIR_NOPEND:
27844318Shibler 			return (1);
27949300Shibler 		case IIR_RXTOUT:
28044318Shibler 		case IIR_RXRDY:
28144318Shibler 			/* do time-critical read in-line */
28244318Shibler 			tp = &dca_tty[unit];
28349300Shibler /*
28449300Shibler  * Process a received byte.  Inline for speed...
28549300Shibler  */
28644318Shibler #ifdef KGDB
28749300Shibler #define	RCVBYTE() \
28849300Shibler 			code = dca->dca_data; \
28949300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
290*50219Skarels 				if (code == FRAME_END && \
291*50219Skarels 				    kgdb_dev == makedev(dcamajor, unit)) \
29249300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
29349300Shibler 			} else \
29449300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
29549300Shibler #else
29649300Shibler #define	RCVBYTE() \
29749300Shibler 			code = dca->dca_data; \
29849300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
29949300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
30044318Shibler #endif
30149300Shibler 			RCVBYTE();
30249300Shibler 			if (dca_hasfifo & (1 << unit)) {
30349300Shibler #ifdef DEBUG
30449300Shibler 				register int fifocnt = 1;
30549300Shibler #endif
30649300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
30749300Shibler 					if (code == LSR_RXRDY) {
30849300Shibler 						RCVBYTE();
30949300Shibler 					} else
31049300Shibler 						dcaeint(unit, code, dca);
31149300Shibler #ifdef DEBUG
31249300Shibler 					fifocnt++;
31349300Shibler #endif
31449300Shibler 				}
31549300Shibler #ifdef DEBUG
31649300Shibler 				if (fifocnt > 16)
31749300Shibler 					fifoin[0]++;
31849300Shibler 				else
31949300Shibler 					fifoin[fifocnt]++;
32049300Shibler #endif
32149300Shibler 			}
32244318Shibler 			break;
32344318Shibler 		case IIR_TXRDY:
32444318Shibler 			tp = &dca_tty[unit];
32544318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
32644318Shibler 			if (tp->t_line)
32744318Shibler 				(*linesw[tp->t_line].l_start)(tp);
32844318Shibler 			else
32944318Shibler 				dcastart(tp);
33044318Shibler 			break;
33144318Shibler 		case IIR_RLS:
33249300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
33344318Shibler 			break;
33444318Shibler 		default:
33544318Shibler 			if (code & IIR_NOPEND)
33644318Shibler 				return (1);
33744318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
33844318Shibler 			    unit, code);
33944318Shibler 			/* fall through */
34044318Shibler 		case IIR_MLSC:
34141480Smckusick 			dcamint(unit, dca);
34244318Shibler 			break;
34344318Shibler 		}
34441480Smckusick 	}
34541480Smckusick }
34641480Smckusick 
34749300Shibler dcaeint(unit, stat, dca)
34849300Shibler 	register int unit, stat;
34941480Smckusick 	register struct dcadevice *dca;
35041480Smckusick {
35141480Smckusick 	register struct tty *tp;
35249300Shibler 	register int c;
35341480Smckusick 
35441480Smckusick 	tp = &dca_tty[unit];
35544318Shibler 	c = dca->dca_data;
35641480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
35741480Smckusick #ifdef KGDB
35841480Smckusick 		/* we don't care about parity errors */
35941480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
36049130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
36149130Skarels 			kgdb_connect(0); /* trap into kgdb */
36241480Smckusick #endif
36341480Smckusick 		return;
36441480Smckusick 	}
36541480Smckusick 	if (stat & (LSR_BI | LSR_FE))
36641480Smckusick 		c |= TTY_FE;
36741480Smckusick 	else if (stat & LSR_PE)
36841480Smckusick 		c |= TTY_PE;
36941480Smckusick 	else if (stat & LSR_OE)
37041480Smckusick 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
37141480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
37241480Smckusick }
37341480Smckusick 
37441480Smckusick dcamint(unit, dca)
37541480Smckusick 	register int unit;
37641480Smckusick 	register struct dcadevice *dca;
37741480Smckusick {
37841480Smckusick 	register struct tty *tp;
37941480Smckusick 	register int stat;
38041480Smckusick 
38141480Smckusick 	tp = &dca_tty[unit];
38241480Smckusick 	stat = dca->dca_msr;
38349300Shibler #ifdef DEBUG
38449300Shibler 	dcamintcount[stat & 0xf]++;
38549300Shibler #endif
38644318Shibler 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
38741480Smckusick 		if (stat & MSR_DCD)
38844318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
38941480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
39041480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
39144318Shibler 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
39244318Shibler 		   (tp->t_flags & CRTSCTS)) {
39344318Shibler 		/* the line is up and we want to do rts/cts flow control */
39444318Shibler 		if (stat & MSR_CTS) {
39544318Shibler 			tp->t_state &=~ TS_TTSTOP;
39644318Shibler 			ttstart(tp);
39744318Shibler 		} else
39844318Shibler 			tp->t_state |= TS_TTSTOP;
39941480Smckusick 	}
40041480Smckusick }
40141480Smckusick 
40241480Smckusick dcaioctl(dev, cmd, data, flag)
40341480Smckusick 	dev_t dev;
40441480Smckusick 	caddr_t data;
40541480Smckusick {
40641480Smckusick 	register struct tty *tp;
40741480Smckusick 	register int unit = UNIT(dev);
40841480Smckusick 	register struct dcadevice *dca;
40941480Smckusick 	register int error;
41041480Smckusick 
41141480Smckusick 	tp = &dca_tty[unit];
41241480Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
41341480Smckusick 	if (error >= 0)
41441480Smckusick 		return (error);
41541480Smckusick 	error = ttioctl(tp, cmd, data, flag);
41641480Smckusick 	if (error >= 0)
41741480Smckusick 		return (error);
41841480Smckusick 
41941480Smckusick 	dca = dca_addr[unit];
42041480Smckusick 	switch (cmd) {
42141480Smckusick 
42241480Smckusick 	case TIOCSBRK:
42341480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
42441480Smckusick 		break;
42541480Smckusick 
42641480Smckusick 	case TIOCCBRK:
42741480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
42841480Smckusick 		break;
42941480Smckusick 
43041480Smckusick 	case TIOCSDTR:
43141480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
43241480Smckusick 		break;
43341480Smckusick 
43441480Smckusick 	case TIOCCDTR:
43541480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
43641480Smckusick 		break;
43741480Smckusick 
43841480Smckusick 	case TIOCMSET:
43941480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
44041480Smckusick 		break;
44141480Smckusick 
44241480Smckusick 	case TIOCMBIS:
44341480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
44441480Smckusick 		break;
44541480Smckusick 
44641480Smckusick 	case TIOCMBIC:
44741480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
44841480Smckusick 		break;
44941480Smckusick 
45041480Smckusick 	case TIOCMGET:
45141480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
45241480Smckusick 		break;
45341480Smckusick 
45441480Smckusick 	default:
45541480Smckusick 		return (ENOTTY);
45641480Smckusick 	}
45741480Smckusick 	return (0);
45841480Smckusick }
45941480Smckusick 
46041480Smckusick dcaparam(tp, t)
46141480Smckusick 	register struct tty *tp;
46241480Smckusick 	register struct termios *t;
46341480Smckusick {
46441480Smckusick 	register struct dcadevice *dca;
46541480Smckusick 	register int cfcr, cflag = t->c_cflag;
46641480Smckusick 	int unit = UNIT(tp->t_dev);
46741480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
46841480Smckusick 
46941480Smckusick 	/* check requested parameters */
47041480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
471*50219Skarels                 return (EINVAL);
47241480Smckusick         /* and copy to tty */
47341480Smckusick         tp->t_ispeed = t->c_ispeed;
47441480Smckusick         tp->t_ospeed = t->c_ospeed;
47541480Smckusick         tp->t_cflag = cflag;
47641480Smckusick 
47741480Smckusick 	dca = dca_addr[unit];
47841480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
47941480Smckusick 	if (ospeed == 0) {
48041480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
481*50219Skarels 		return (0);
48241480Smckusick 	}
48341480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
48441480Smckusick 	dca->dca_data = ospeed & 0xFF;
48541480Smckusick 	dca->dca_ier = ospeed >> 8;
48641480Smckusick 	switch (cflag&CSIZE) {
48741480Smckusick 	case CS5:
48841480Smckusick 		cfcr = CFCR_5BITS; break;
48941480Smckusick 	case CS6:
49041480Smckusick 		cfcr = CFCR_6BITS; break;
49141480Smckusick 	case CS7:
49241480Smckusick 		cfcr = CFCR_7BITS; break;
49341480Smckusick 	case CS8:
49441480Smckusick 		cfcr = CFCR_8BITS; break;
49541480Smckusick 	}
49641480Smckusick 	if (cflag&PARENB) {
49741480Smckusick 		cfcr |= CFCR_PENAB;
49841480Smckusick 		if ((cflag&PARODD) == 0)
49941480Smckusick 			cfcr |= CFCR_PEVEN;
50041480Smckusick 	}
50141480Smckusick 	if (cflag&CSTOPB)
50241480Smckusick 		cfcr |= CFCR_STOPB;
50341480Smckusick 	dca->dca_cfcr = cfcr;
50449300Shibler 	if (dca_hasfifo & (1 << unit))
50549300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
506*50219Skarels 	return (0);
50741480Smckusick }
50841480Smckusick 
50941480Smckusick dcastart(tp)
51041480Smckusick 	register struct tty *tp;
51141480Smckusick {
51241480Smckusick 	register struct dcadevice *dca;
51341480Smckusick 	int s, unit, c;
51441480Smckusick 
51541480Smckusick 	unit = UNIT(tp->t_dev);
51641480Smckusick 	dca = dca_addr[unit];
51741480Smckusick 	s = spltty();
51844318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
51941480Smckusick 		goto out;
52041480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
52141480Smckusick 		if (tp->t_state&TS_ASLEEP) {
52241480Smckusick 			tp->t_state &= ~TS_ASLEEP;
52341480Smckusick 			wakeup((caddr_t)&tp->t_outq);
52441480Smckusick 		}
52541480Smckusick 		if (tp->t_wsel) {
52641480Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
52741480Smckusick 			tp->t_wsel = 0;
52841480Smckusick 			tp->t_state &= ~TS_WCOLL;
52941480Smckusick 		}
53041480Smckusick 	}
53141480Smckusick 	if (tp->t_outq.c_cc == 0)
53241480Smckusick 		goto out;
53344318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
53444318Shibler 		c = getc(&tp->t_outq);
53544318Shibler 		tp->t_state |= TS_BUSY;
53644318Shibler 		dca->dca_data = c;
53749300Shibler 		if (dca_hasfifo & (1 << unit)) {
53849300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
53949300Shibler 				dca->dca_data = getc(&tp->t_outq);
54049300Shibler #ifdef DEBUG
54149300Shibler 			if (c > 16)
54249300Shibler 				fifoout[0]++;
54349300Shibler 			else
54449300Shibler 				fifoout[c]++;
54549300Shibler #endif
54649300Shibler 		}
54744318Shibler 	}
54841480Smckusick out:
54941480Smckusick 	splx(s);
55041480Smckusick }
55141480Smckusick 
55241480Smckusick /*
55341480Smckusick  * Stop output on a line.
55441480Smckusick  */
55541480Smckusick /*ARGSUSED*/
55641480Smckusick dcastop(tp, flag)
55741480Smckusick 	register struct tty *tp;
55841480Smckusick {
55941480Smckusick 	register int s;
56041480Smckusick 
56141480Smckusick 	s = spltty();
56241480Smckusick 	if (tp->t_state & TS_BUSY) {
56341480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
56441480Smckusick 			tp->t_state |= TS_FLUSH;
56541480Smckusick 	}
56641480Smckusick 	splx(s);
56741480Smckusick }
56841480Smckusick 
56941480Smckusick dcamctl(dev, bits, how)
57041480Smckusick 	dev_t dev;
57141480Smckusick 	int bits, how;
57241480Smckusick {
57341480Smckusick 	register struct dcadevice *dca;
57441480Smckusick 	register int unit;
57541480Smckusick 	int s;
57641480Smckusick 
57741480Smckusick 	unit = UNIT(dev);
57841480Smckusick 	dca = dca_addr[unit];
57941480Smckusick 	s = spltty();
58041480Smckusick 	switch (how) {
58141480Smckusick 
58241480Smckusick 	case DMSET:
58341480Smckusick 		dca->dca_mcr = bits;
58441480Smckusick 		break;
58541480Smckusick 
58641480Smckusick 	case DMBIS:
58741480Smckusick 		dca->dca_mcr |= bits;
58841480Smckusick 		break;
58941480Smckusick 
59041480Smckusick 	case DMBIC:
59141480Smckusick 		dca->dca_mcr &= ~bits;
59241480Smckusick 		break;
59341480Smckusick 
59441480Smckusick 	case DMGET:
59541480Smckusick 		bits = dca->dca_msr;
59641480Smckusick 		break;
59741480Smckusick 	}
59841480Smckusick 	(void) splx(s);
599*50219Skarels 	return (bits);
60041480Smckusick }
60141480Smckusick 
60241480Smckusick /*
60341480Smckusick  * Following are all routines needed for DCA to act as console
60441480Smckusick  */
60545788Sbostic #include "../hp300/cons.h"
60641480Smckusick 
60741480Smckusick dcacnprobe(cp)
60841480Smckusick 	struct consdev *cp;
60941480Smckusick {
61049300Shibler 	int unit;
61141480Smckusick 
61249130Skarels 	/* locate the major number */
61349130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
61449130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
61549130Skarels 			break;
61649130Skarels 
61741480Smckusick 	/* XXX: ick */
61841480Smckusick 	unit = CONUNIT;
61949300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
62041480Smckusick 
62141480Smckusick 	/* make sure hardware exists */
62241480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
62341480Smckusick 		cp->cn_pri = CN_DEAD;
62441480Smckusick 		return;
62541480Smckusick 	}
62641480Smckusick 
62741480Smckusick 	/* initialize required fields */
62849130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
62941480Smckusick 	cp->cn_tp = &dca_tty[unit];
63041480Smckusick 	switch (dca_addr[unit]->dca_irid) {
63141480Smckusick 	case DCAID0:
63241480Smckusick 	case DCAID1:
63341480Smckusick 		cp->cn_pri = CN_NORMAL;
63441480Smckusick 		break;
63541480Smckusick 	case DCAREMID0:
63641480Smckusick 	case DCAREMID1:
63741480Smckusick 		cp->cn_pri = CN_REMOTE;
63841480Smckusick 		break;
63941480Smckusick 	default:
64041480Smckusick 		cp->cn_pri = CN_DEAD;
64141480Smckusick 		break;
64241480Smckusick 	}
64349130Skarels 	/*
64449300Shibler 	 * If dcaconsole is initialized, raise our priority.
64549130Skarels 	 */
64649130Skarels 	if (dcaconsole == unit)
64749130Skarels 		cp->cn_pri = CN_REMOTE;
64849300Shibler #ifdef KGDB
64949130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
65049130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
65149300Shibler #endif
65241480Smckusick }
65341480Smckusick 
65441480Smckusick dcacninit(cp)
65541480Smckusick 	struct consdev *cp;
65641480Smckusick {
65741480Smckusick 	int unit = UNIT(cp->cn_dev);
65841480Smckusick 
65949130Skarels 	dcainit(unit, dcadefaultrate);
66041480Smckusick 	dcaconsole = unit;
66149130Skarels 	dcaconsinit = 1;
66241480Smckusick }
66341480Smckusick 
66449130Skarels dcainit(unit, rate)
66549130Skarels 	int unit, rate;
66641480Smckusick {
66741480Smckusick 	register struct dcadevice *dca;
66849130Skarels 	int s;
66941480Smckusick 	short stat;
67041480Smckusick 
67141480Smckusick #ifdef lint
67241480Smckusick 	stat = unit; if (stat) return;
67341480Smckusick #endif
67441480Smckusick 	dca = dca_addr[unit];
67541480Smckusick 	s = splhigh();
67641480Smckusick 	dca->dca_irid = 0xFF;
67741480Smckusick 	DELAY(100);
67841480Smckusick 	dca->dca_ic = IC_IE;
67941480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
68049130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
68141480Smckusick 	dca->dca_data = rate & 0xFF;
68241480Smckusick 	dca->dca_ier = rate >> 8;
68341480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
68441480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
68549300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
68641480Smckusick 	stat = dca->dca_iir;
68741480Smckusick 	splx(s);
68841480Smckusick }
68941480Smckusick 
69041480Smckusick dcacngetc(dev)
69141480Smckusick {
69241480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
69341480Smckusick 	short stat;
69441480Smckusick 	int c, s;
69541480Smckusick 
69641480Smckusick #ifdef lint
697*50219Skarels 	stat = dev; if (stat) return (0);
69841480Smckusick #endif
69941480Smckusick 	s = splhigh();
70041480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
70141480Smckusick 		;
70241480Smckusick 	c = dca->dca_data;
70341480Smckusick 	stat = dca->dca_iir;
70441480Smckusick 	splx(s);
705*50219Skarels 	return (c);
70641480Smckusick }
70741480Smckusick 
70841480Smckusick /*
70941480Smckusick  * Console kernel output character routine.
71041480Smckusick  */
71141480Smckusick dcacnputc(dev, c)
71241480Smckusick 	dev_t dev;
71341480Smckusick 	register int c;
71441480Smckusick {
71541480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
71641480Smckusick 	register int timo;
71741480Smckusick 	short stat;
71841480Smckusick 	int s = splhigh();
71941480Smckusick 
72041480Smckusick #ifdef lint
72141480Smckusick 	stat = dev; if (stat) return;
72241480Smckusick #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