xref: /csrg-svn/sys/hp/dev/dca.c (revision 52389)
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*52389Smckusick  *	@(#)dca.c	7.13 (Berkeley) 02/05/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"
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 
37*52389Smckusick void	dcastart();
38*52389Smckusick 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 
40341480Smckusick dcaioctl(dev, cmd, data, flag)
40441480Smckusick 	dev_t dev;
40541480Smckusick 	caddr_t data;
40641480Smckusick {
40741480Smckusick 	register struct tty *tp;
40841480Smckusick 	register int unit = UNIT(dev);
40941480Smckusick 	register struct dcadevice *dca;
41041480Smckusick 	register int error;
41141480Smckusick 
41241480Smckusick 	tp = &dca_tty[unit];
41341480Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
41441480Smckusick 	if (error >= 0)
41541480Smckusick 		return (error);
41641480Smckusick 	error = ttioctl(tp, cmd, data, flag);
41741480Smckusick 	if (error >= 0)
41841480Smckusick 		return (error);
41941480Smckusick 
42041480Smckusick 	dca = dca_addr[unit];
42141480Smckusick 	switch (cmd) {
42241480Smckusick 
42341480Smckusick 	case TIOCSBRK:
42441480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
42541480Smckusick 		break;
42641480Smckusick 
42741480Smckusick 	case TIOCCBRK:
42841480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
42941480Smckusick 		break;
43041480Smckusick 
43141480Smckusick 	case TIOCSDTR:
43241480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
43341480Smckusick 		break;
43441480Smckusick 
43541480Smckusick 	case TIOCCDTR:
43641480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
43741480Smckusick 		break;
43841480Smckusick 
43941480Smckusick 	case TIOCMSET:
44041480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
44141480Smckusick 		break;
44241480Smckusick 
44341480Smckusick 	case TIOCMBIS:
44441480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
44541480Smckusick 		break;
44641480Smckusick 
44741480Smckusick 	case TIOCMBIC:
44841480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
44941480Smckusick 		break;
45041480Smckusick 
45141480Smckusick 	case TIOCMGET:
45241480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
45341480Smckusick 		break;
45441480Smckusick 
45541480Smckusick 	default:
45641480Smckusick 		return (ENOTTY);
45741480Smckusick 	}
45841480Smckusick 	return (0);
45941480Smckusick }
46041480Smckusick 
46141480Smckusick dcaparam(tp, t)
46241480Smckusick 	register struct tty *tp;
46341480Smckusick 	register struct termios *t;
46441480Smckusick {
46541480Smckusick 	register struct dcadevice *dca;
46641480Smckusick 	register int cfcr, cflag = t->c_cflag;
46741480Smckusick 	int unit = UNIT(tp->t_dev);
46841480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
46941480Smckusick 
47041480Smckusick 	/* check requested parameters */
47141480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
47250219Skarels                 return (EINVAL);
47341480Smckusick         /* and copy to tty */
47441480Smckusick         tp->t_ispeed = t->c_ispeed;
47541480Smckusick         tp->t_ospeed = t->c_ospeed;
47641480Smckusick         tp->t_cflag = cflag;
47741480Smckusick 
47841480Smckusick 	dca = dca_addr[unit];
47941480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
48041480Smckusick 	if (ospeed == 0) {
48141480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
48250219Skarels 		return (0);
48341480Smckusick 	}
48441480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
48541480Smckusick 	dca->dca_data = ospeed & 0xFF;
48641480Smckusick 	dca->dca_ier = ospeed >> 8;
48741480Smckusick 	switch (cflag&CSIZE) {
48841480Smckusick 	case CS5:
48941480Smckusick 		cfcr = CFCR_5BITS; break;
49041480Smckusick 	case CS6:
49141480Smckusick 		cfcr = CFCR_6BITS; break;
49241480Smckusick 	case CS7:
49341480Smckusick 		cfcr = CFCR_7BITS; break;
49441480Smckusick 	case CS8:
49541480Smckusick 		cfcr = CFCR_8BITS; break;
49641480Smckusick 	}
49741480Smckusick 	if (cflag&PARENB) {
49841480Smckusick 		cfcr |= CFCR_PENAB;
49941480Smckusick 		if ((cflag&PARODD) == 0)
50041480Smckusick 			cfcr |= CFCR_PEVEN;
50141480Smckusick 	}
50241480Smckusick 	if (cflag&CSTOPB)
50341480Smckusick 		cfcr |= CFCR_STOPB;
50441480Smckusick 	dca->dca_cfcr = cfcr;
50549300Shibler 	if (dca_hasfifo & (1 << unit))
50649300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
50750219Skarels 	return (0);
50841480Smckusick }
50941480Smckusick 
510*52389Smckusick void
51141480Smckusick dcastart(tp)
51241480Smckusick 	register struct tty *tp;
51341480Smckusick {
51441480Smckusick 	register struct dcadevice *dca;
51541480Smckusick 	int s, unit, c;
51641480Smckusick 
51741480Smckusick 	unit = UNIT(tp->t_dev);
51841480Smckusick 	dca = dca_addr[unit];
51941480Smckusick 	s = spltty();
52044318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
52141480Smckusick 		goto out;
52241480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
52341480Smckusick 		if (tp->t_state&TS_ASLEEP) {
52441480Smckusick 			tp->t_state &= ~TS_ASLEEP;
52541480Smckusick 			wakeup((caddr_t)&tp->t_outq);
52641480Smckusick 		}
52741480Smckusick 		if (tp->t_wsel) {
52841480Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
52941480Smckusick 			tp->t_wsel = 0;
53041480Smckusick 			tp->t_state &= ~TS_WCOLL;
53141480Smckusick 		}
53241480Smckusick 	}
53341480Smckusick 	if (tp->t_outq.c_cc == 0)
53441480Smckusick 		goto out;
53544318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
53644318Shibler 		c = getc(&tp->t_outq);
53744318Shibler 		tp->t_state |= TS_BUSY;
53844318Shibler 		dca->dca_data = c;
53949300Shibler 		if (dca_hasfifo & (1 << unit)) {
54049300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
54149300Shibler 				dca->dca_data = getc(&tp->t_outq);
54249300Shibler #ifdef DEBUG
54349300Shibler 			if (c > 16)
54449300Shibler 				fifoout[0]++;
54549300Shibler 			else
54649300Shibler 				fifoout[c]++;
54749300Shibler #endif
54849300Shibler 		}
54944318Shibler 	}
55041480Smckusick out:
55141480Smckusick 	splx(s);
55241480Smckusick }
55341480Smckusick 
55441480Smckusick /*
55541480Smckusick  * Stop output on a line.
55641480Smckusick  */
55741480Smckusick /*ARGSUSED*/
55841480Smckusick dcastop(tp, flag)
55941480Smckusick 	register struct tty *tp;
56041480Smckusick {
56141480Smckusick 	register int s;
56241480Smckusick 
56341480Smckusick 	s = spltty();
56441480Smckusick 	if (tp->t_state & TS_BUSY) {
56541480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
56641480Smckusick 			tp->t_state |= TS_FLUSH;
56741480Smckusick 	}
56841480Smckusick 	splx(s);
56941480Smckusick }
57041480Smckusick 
57141480Smckusick dcamctl(dev, bits, how)
57241480Smckusick 	dev_t dev;
57341480Smckusick 	int bits, how;
57441480Smckusick {
57541480Smckusick 	register struct dcadevice *dca;
57641480Smckusick 	register int unit;
57741480Smckusick 	int s;
57841480Smckusick 
57941480Smckusick 	unit = UNIT(dev);
58041480Smckusick 	dca = dca_addr[unit];
58141480Smckusick 	s = spltty();
58241480Smckusick 	switch (how) {
58341480Smckusick 
58441480Smckusick 	case DMSET:
58541480Smckusick 		dca->dca_mcr = bits;
58641480Smckusick 		break;
58741480Smckusick 
58841480Smckusick 	case DMBIS:
58941480Smckusick 		dca->dca_mcr |= bits;
59041480Smckusick 		break;
59141480Smckusick 
59241480Smckusick 	case DMBIC:
59341480Smckusick 		dca->dca_mcr &= ~bits;
59441480Smckusick 		break;
59541480Smckusick 
59641480Smckusick 	case DMGET:
59741480Smckusick 		bits = dca->dca_msr;
59841480Smckusick 		break;
59941480Smckusick 	}
60041480Smckusick 	(void) splx(s);
60150219Skarels 	return (bits);
60241480Smckusick }
60341480Smckusick 
60441480Smckusick /*
60541480Smckusick  * Following are all routines needed for DCA to act as console
60641480Smckusick  */
60745788Sbostic #include "../hp300/cons.h"
60841480Smckusick 
60941480Smckusick dcacnprobe(cp)
61041480Smckusick 	struct consdev *cp;
61141480Smckusick {
61249300Shibler 	int unit;
61341480Smckusick 
61449130Skarels 	/* locate the major number */
61549130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
61649130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
61749130Skarels 			break;
61849130Skarels 
61941480Smckusick 	/* XXX: ick */
62041480Smckusick 	unit = CONUNIT;
62149300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
62241480Smckusick 
62341480Smckusick 	/* make sure hardware exists */
62441480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
62541480Smckusick 		cp->cn_pri = CN_DEAD;
62641480Smckusick 		return;
62741480Smckusick 	}
62841480Smckusick 
62941480Smckusick 	/* initialize required fields */
63049130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
63141480Smckusick 	cp->cn_tp = &dca_tty[unit];
63241480Smckusick 	switch (dca_addr[unit]->dca_irid) {
63341480Smckusick 	case DCAID0:
63441480Smckusick 	case DCAID1:
63541480Smckusick 		cp->cn_pri = CN_NORMAL;
63641480Smckusick 		break;
63741480Smckusick 	case DCAREMID0:
63841480Smckusick 	case DCAREMID1:
63941480Smckusick 		cp->cn_pri = CN_REMOTE;
64041480Smckusick 		break;
64141480Smckusick 	default:
64241480Smckusick 		cp->cn_pri = CN_DEAD;
64341480Smckusick 		break;
64441480Smckusick 	}
64549130Skarels 	/*
64649300Shibler 	 * If dcaconsole is initialized, raise our priority.
64749130Skarels 	 */
64849130Skarels 	if (dcaconsole == unit)
64949130Skarels 		cp->cn_pri = CN_REMOTE;
65049300Shibler #ifdef KGDB
65149130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
65249130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
65349300Shibler #endif
65441480Smckusick }
65541480Smckusick 
65641480Smckusick dcacninit(cp)
65741480Smckusick 	struct consdev *cp;
65841480Smckusick {
65941480Smckusick 	int unit = UNIT(cp->cn_dev);
66041480Smckusick 
66149130Skarels 	dcainit(unit, dcadefaultrate);
66241480Smckusick 	dcaconsole = unit;
66349130Skarels 	dcaconsinit = 1;
66441480Smckusick }
66541480Smckusick 
66649130Skarels dcainit(unit, rate)
66749130Skarels 	int unit, rate;
66841480Smckusick {
66941480Smckusick 	register struct dcadevice *dca;
67049130Skarels 	int s;
67141480Smckusick 	short stat;
67241480Smckusick 
67341480Smckusick #ifdef lint
67441480Smckusick 	stat = unit; if (stat) return;
67541480Smckusick #endif
67641480Smckusick 	dca = dca_addr[unit];
67741480Smckusick 	s = splhigh();
67841480Smckusick 	dca->dca_irid = 0xFF;
67941480Smckusick 	DELAY(100);
68041480Smckusick 	dca->dca_ic = IC_IE;
68141480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
68249130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
68341480Smckusick 	dca->dca_data = rate & 0xFF;
68441480Smckusick 	dca->dca_ier = rate >> 8;
68541480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
68641480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
68749300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
68841480Smckusick 	stat = dca->dca_iir;
68941480Smckusick 	splx(s);
69041480Smckusick }
69141480Smckusick 
69241480Smckusick dcacngetc(dev)
69341480Smckusick {
69441480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
69541480Smckusick 	short stat;
69641480Smckusick 	int c, s;
69741480Smckusick 
69841480Smckusick #ifdef lint
69950219Skarels 	stat = dev; if (stat) return (0);
70041480Smckusick #endif
70141480Smckusick 	s = splhigh();
70241480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
70341480Smckusick 		;
70441480Smckusick 	c = dca->dca_data;
70541480Smckusick 	stat = dca->dca_iir;
70641480Smckusick 	splx(s);
70750219Skarels 	return (c);
70841480Smckusick }
70941480Smckusick 
71041480Smckusick /*
71141480Smckusick  * Console kernel output character routine.
71241480Smckusick  */
71341480Smckusick dcacnputc(dev, c)
71441480Smckusick 	dev_t dev;
71541480Smckusick 	register int c;
71641480Smckusick {
71741480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
71841480Smckusick 	register int timo;
71941480Smckusick 	short stat;
72041480Smckusick 	int s = splhigh();
72141480Smckusick 
72241480Smckusick #ifdef lint
72341480Smckusick 	stat = dev; if (stat) return;
72441480Smckusick #endif
72549130Skarels 	if (dcaconsinit == 0) {
72649130Skarels 		(void) dcainit(UNIT(dev), dcadefaultrate);
72749130Skarels 		dcaconsinit = 1;
72841480Smckusick 	}
72941480Smckusick 	/* wait for any pending transmission to finish */
73041480Smckusick 	timo = 50000;
73141480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
73241480Smckusick 		;
73341480Smckusick 	dca->dca_data = c;
73441480Smckusick 	/* wait for this transmission to complete */
73541480Smckusick 	timo = 1500000;
73641480Smckusick 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
73741480Smckusick 		;
73841480Smckusick 	/* clear any interrupts generated by this transmission */
73941480Smckusick 	stat = dca->dca_iir;
74041480Smckusick 	splx(s);
74141480Smckusick }
74241480Smckusick #endif
743