xref: /csrg-svn/sys/hp/dev/dca.c (revision 49750)
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*49750Smarc  *	@(#)dca.c	7.11 (Berkeley) 05/16/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 
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 
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)
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*/
207*49750Smarc dcaclose(dev, flag, mode, p)
20841480Smckusick 	dev_t dev;
209*49750Smarc 	int flag, mode;
210*49750Smarc 	struct proc *p;
21141480Smckusick {
21241480Smckusick 	register struct tty *tp;
21341480Smckusick 	register struct dcadevice *dca;
21441480Smckusick 	register int unit;
21541480Smckusick 
21641480Smckusick 	unit = UNIT(dev);
21741480Smckusick 	dca = dca_addr[unit];
21841480Smckusick 	tp = &dca_tty[unit];
219*49750Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
22041480Smckusick 	dca->dca_cfcr &= ~CFCR_SBREAK;
22141480Smckusick #ifdef KGDB
22241480Smckusick 	/* do not disable interrupts if debugging */
22349130Skarels 	if (dev != kgdb_dev)
22441480Smckusick #endif
22541480Smckusick 	dca->dca_ier = 0;
22649130Skarels 	(void) dcamctl(dev, 0, DMSET);
22749130Skarels 	if (tp->t_state & TS_HUPCLS)
22849130Skarels 		(*linesw[tp->t_line].l_modem)(tp, 0);
22941480Smckusick 	ttyclose(tp);
23041480Smckusick 	return(0);
23141480Smckusick }
23241480Smckusick 
23341480Smckusick dcaread(dev, uio, flag)
23441480Smckusick 	dev_t dev;
23541480Smckusick 	struct uio *uio;
23641480Smckusick {
23741480Smckusick 	register struct tty *tp = &dca_tty[UNIT(dev)];
23841480Smckusick 
23941480Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
24041480Smckusick }
24141480Smckusick 
24241480Smckusick dcawrite(dev, uio, flag)
24341480Smckusick 	dev_t dev;
24441480Smckusick 	struct uio *uio;
24541480Smckusick {
24641480Smckusick 	int unit = UNIT(dev);
24741480Smckusick 	register struct tty *tp = &dca_tty[unit];
24841480Smckusick 
24942353Smckusick 	/*
25042353Smckusick 	 * (XXX) We disallow virtual consoles if the physical console is
25142353Smckusick 	 * a serial port.  This is in case there is a display attached that
25242353Smckusick 	 * is not the console.  In that situation we don't need/want the X
25342353Smckusick 	 * server taking over the console.
25442353Smckusick 	 */
25542353Smckusick 	if (constty && unit == dcaconsole)
25642353Smckusick 		constty = NULL;
25741480Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
25841480Smckusick }
25941480Smckusick 
26041480Smckusick dcaintr(unit)
26141480Smckusick 	register int unit;
26241480Smckusick {
26341480Smckusick 	register struct dcadevice *dca;
26444318Shibler 	register u_char code;
26544318Shibler 	register struct tty *tp;
26641480Smckusick 
26741480Smckusick 	dca = dca_addr[unit];
26841480Smckusick 	if ((dca->dca_ic & IC_IR) == 0)
26941480Smckusick 		return(0);
27044318Shibler 	while (1) {
27144318Shibler 		code = dca->dca_iir;
27249300Shibler #ifdef DEBUG
27349300Shibler 		dcaintrcount[code & IIR_IMASK]++;
27449300Shibler #endif
27549300Shibler 		switch (code & IIR_IMASK) {
27644318Shibler 		case IIR_NOPEND:
27744318Shibler 			return (1);
27849300Shibler 		case IIR_RXTOUT:
27944318Shibler 		case IIR_RXRDY:
28044318Shibler 			/* do time-critical read in-line */
28144318Shibler 			tp = &dca_tty[unit];
28249300Shibler /*
28349300Shibler  * Process a received byte.  Inline for speed...
28449300Shibler  */
28544318Shibler #ifdef KGDB
28649300Shibler #define	RCVBYTE() \
28749300Shibler 			code = dca->dca_data; \
28849300Shibler 			if ((tp->t_state & TS_ISOPEN) == 0) { \
28949300Shibler 				if (kgdb_dev == makedev(dcamajor, unit) && \
29049300Shibler 				    code == FRAME_END) \
29149300Shibler 					kgdb_connect(0); /* trap into kgdb */ \
29249300Shibler 			} else \
29349300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
29449300Shibler #else
29549300Shibler #define	RCVBYTE() \
29649300Shibler 			code = dca->dca_data; \
29749300Shibler 			if ((tp->t_state & TS_ISOPEN) != 0) \
29849300Shibler 				(*linesw[tp->t_line].l_rint)(code, tp)
29944318Shibler #endif
30049300Shibler 			RCVBYTE();
30149300Shibler 			if (dca_hasfifo & (1 << unit)) {
30249300Shibler #ifdef DEBUG
30349300Shibler 				register int fifocnt = 1;
30449300Shibler #endif
30549300Shibler 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
30649300Shibler 					if (code == LSR_RXRDY) {
30749300Shibler 						RCVBYTE();
30849300Shibler 					} else
30949300Shibler 						dcaeint(unit, code, dca);
31049300Shibler #ifdef DEBUG
31149300Shibler 					fifocnt++;
31249300Shibler #endif
31349300Shibler 				}
31449300Shibler #ifdef DEBUG
31549300Shibler 				if (fifocnt > 16)
31649300Shibler 					fifoin[0]++;
31749300Shibler 				else
31849300Shibler 					fifoin[fifocnt]++;
31949300Shibler #endif
32049300Shibler 			}
32144318Shibler 			break;
32244318Shibler 		case IIR_TXRDY:
32344318Shibler 			tp = &dca_tty[unit];
32444318Shibler 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
32544318Shibler 			if (tp->t_line)
32644318Shibler 				(*linesw[tp->t_line].l_start)(tp);
32744318Shibler 			else
32844318Shibler 				dcastart(tp);
32944318Shibler 			break;
33044318Shibler 		case IIR_RLS:
33149300Shibler 			dcaeint(unit, dca->dca_lsr, dca);
33244318Shibler 			break;
33344318Shibler 		default:
33444318Shibler 			if (code & IIR_NOPEND)
33544318Shibler 				return (1);
33644318Shibler 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
33744318Shibler 			    unit, code);
33844318Shibler 			/* fall through */
33944318Shibler 		case IIR_MLSC:
34041480Smckusick 			dcamint(unit, dca);
34144318Shibler 			break;
34244318Shibler 		}
34341480Smckusick 	}
34441480Smckusick }
34541480Smckusick 
34649300Shibler dcaeint(unit, stat, dca)
34749300Shibler 	register int unit, stat;
34841480Smckusick 	register struct dcadevice *dca;
34941480Smckusick {
35041480Smckusick 	register struct tty *tp;
35149300Shibler 	register int c;
35241480Smckusick 
35341480Smckusick 	tp = &dca_tty[unit];
35444318Shibler 	c = dca->dca_data;
35541480Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
35641480Smckusick #ifdef KGDB
35741480Smckusick 		/* we don't care about parity errors */
35841480Smckusick 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
35949130Skarels 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
36049130Skarels 			kgdb_connect(0); /* trap into kgdb */
36141480Smckusick #endif
36241480Smckusick 		return;
36341480Smckusick 	}
36441480Smckusick 	if (stat & (LSR_BI | LSR_FE))
36541480Smckusick 		c |= TTY_FE;
36641480Smckusick 	else if (stat & LSR_PE)
36741480Smckusick 		c |= TTY_PE;
36841480Smckusick 	else if (stat & LSR_OE)
36941480Smckusick 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
37041480Smckusick 	(*linesw[tp->t_line].l_rint)(c, tp);
37141480Smckusick }
37241480Smckusick 
37341480Smckusick dcamint(unit, dca)
37441480Smckusick 	register int unit;
37541480Smckusick 	register struct dcadevice *dca;
37641480Smckusick {
37741480Smckusick 	register struct tty *tp;
37841480Smckusick 	register int stat;
37941480Smckusick 
38041480Smckusick 	tp = &dca_tty[unit];
38141480Smckusick 	stat = dca->dca_msr;
38249300Shibler #ifdef DEBUG
38349300Shibler 	dcamintcount[stat & 0xf]++;
38449300Shibler #endif
38544318Shibler 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
38641480Smckusick 		if (stat & MSR_DCD)
38744318Shibler 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
38841480Smckusick 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
38941480Smckusick 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
39044318Shibler 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
39144318Shibler 		   (tp->t_flags & CRTSCTS)) {
39244318Shibler 		/* the line is up and we want to do rts/cts flow control */
39344318Shibler 		if (stat & MSR_CTS) {
39444318Shibler 			tp->t_state &=~ TS_TTSTOP;
39544318Shibler 			ttstart(tp);
39644318Shibler 		} else
39744318Shibler 			tp->t_state |= TS_TTSTOP;
39841480Smckusick 	}
39941480Smckusick }
40041480Smckusick 
40141480Smckusick dcaioctl(dev, cmd, data, flag)
40241480Smckusick 	dev_t dev;
40341480Smckusick 	caddr_t data;
40441480Smckusick {
40541480Smckusick 	register struct tty *tp;
40641480Smckusick 	register int unit = UNIT(dev);
40741480Smckusick 	register struct dcadevice *dca;
40841480Smckusick 	register int error;
40941480Smckusick 
41041480Smckusick 	tp = &dca_tty[unit];
41141480Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
41241480Smckusick 	if (error >= 0)
41341480Smckusick 		return (error);
41441480Smckusick 	error = ttioctl(tp, cmd, data, flag);
41541480Smckusick 	if (error >= 0)
41641480Smckusick 		return (error);
41741480Smckusick 
41841480Smckusick 	dca = dca_addr[unit];
41941480Smckusick 	switch (cmd) {
42041480Smckusick 
42141480Smckusick 	case TIOCSBRK:
42241480Smckusick 		dca->dca_cfcr |= CFCR_SBREAK;
42341480Smckusick 		break;
42441480Smckusick 
42541480Smckusick 	case TIOCCBRK:
42641480Smckusick 		dca->dca_cfcr &= ~CFCR_SBREAK;
42741480Smckusick 		break;
42841480Smckusick 
42941480Smckusick 	case TIOCSDTR:
43041480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
43141480Smckusick 		break;
43241480Smckusick 
43341480Smckusick 	case TIOCCDTR:
43441480Smckusick 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
43541480Smckusick 		break;
43641480Smckusick 
43741480Smckusick 	case TIOCMSET:
43841480Smckusick 		(void) dcamctl(dev, *(int *)data, DMSET);
43941480Smckusick 		break;
44041480Smckusick 
44141480Smckusick 	case TIOCMBIS:
44241480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIS);
44341480Smckusick 		break;
44441480Smckusick 
44541480Smckusick 	case TIOCMBIC:
44641480Smckusick 		(void) dcamctl(dev, *(int *)data, DMBIC);
44741480Smckusick 		break;
44841480Smckusick 
44941480Smckusick 	case TIOCMGET:
45041480Smckusick 		*(int *)data = dcamctl(dev, 0, DMGET);
45141480Smckusick 		break;
45241480Smckusick 
45341480Smckusick 	default:
45441480Smckusick 		return (ENOTTY);
45541480Smckusick 	}
45641480Smckusick 	return (0);
45741480Smckusick }
45841480Smckusick 
45941480Smckusick dcaparam(tp, t)
46041480Smckusick 	register struct tty *tp;
46141480Smckusick 	register struct termios *t;
46241480Smckusick {
46341480Smckusick 	register struct dcadevice *dca;
46441480Smckusick 	register int cfcr, cflag = t->c_cflag;
46541480Smckusick 	int unit = UNIT(tp->t_dev);
46641480Smckusick 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
46741480Smckusick 
46841480Smckusick 	/* check requested parameters */
46941480Smckusick         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
47041480Smckusick                 return(EINVAL);
47141480Smckusick         /* and copy to tty */
47241480Smckusick         tp->t_ispeed = t->c_ispeed;
47341480Smckusick         tp->t_ospeed = t->c_ospeed;
47441480Smckusick         tp->t_cflag = cflag;
47541480Smckusick 
47641480Smckusick 	dca = dca_addr[unit];
47741480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
47841480Smckusick 	if (ospeed == 0) {
47941480Smckusick 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
48041480Smckusick 		return(0);
48141480Smckusick 	}
48241480Smckusick 	dca->dca_cfcr |= CFCR_DLAB;
48341480Smckusick 	dca->dca_data = ospeed & 0xFF;
48441480Smckusick 	dca->dca_ier = ospeed >> 8;
48541480Smckusick 	switch (cflag&CSIZE) {
48641480Smckusick 	case CS5:
48741480Smckusick 		cfcr = CFCR_5BITS; break;
48841480Smckusick 	case CS6:
48941480Smckusick 		cfcr = CFCR_6BITS; break;
49041480Smckusick 	case CS7:
49141480Smckusick 		cfcr = CFCR_7BITS; break;
49241480Smckusick 	case CS8:
49341480Smckusick 		cfcr = CFCR_8BITS; break;
49441480Smckusick 	}
49541480Smckusick 	if (cflag&PARENB) {
49641480Smckusick 		cfcr |= CFCR_PENAB;
49741480Smckusick 		if ((cflag&PARODD) == 0)
49841480Smckusick 			cfcr |= CFCR_PEVEN;
49941480Smckusick 	}
50041480Smckusick 	if (cflag&CSTOPB)
50141480Smckusick 		cfcr |= CFCR_STOPB;
50241480Smckusick 	dca->dca_cfcr = cfcr;
50349300Shibler 	if (dca_hasfifo & (1 << unit))
50449300Shibler 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
50541480Smckusick 	return(0);
50641480Smckusick }
50741480Smckusick 
50841480Smckusick dcastart(tp)
50941480Smckusick 	register struct tty *tp;
51041480Smckusick {
51141480Smckusick 	register struct dcadevice *dca;
51241480Smckusick 	int s, unit, c;
51341480Smckusick 
51441480Smckusick 	unit = UNIT(tp->t_dev);
51541480Smckusick 	dca = dca_addr[unit];
51641480Smckusick 	s = spltty();
51744318Shibler 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
51841480Smckusick 		goto out;
51941480Smckusick 	if (tp->t_outq.c_cc <= tp->t_lowat) {
52041480Smckusick 		if (tp->t_state&TS_ASLEEP) {
52141480Smckusick 			tp->t_state &= ~TS_ASLEEP;
52241480Smckusick 			wakeup((caddr_t)&tp->t_outq);
52341480Smckusick 		}
52441480Smckusick 		if (tp->t_wsel) {
52541480Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
52641480Smckusick 			tp->t_wsel = 0;
52741480Smckusick 			tp->t_state &= ~TS_WCOLL;
52841480Smckusick 		}
52941480Smckusick 	}
53041480Smckusick 	if (tp->t_outq.c_cc == 0)
53141480Smckusick 		goto out;
53244318Shibler 	if (dca->dca_lsr & LSR_TXRDY) {
53344318Shibler 		c = getc(&tp->t_outq);
53444318Shibler 		tp->t_state |= TS_BUSY;
53544318Shibler 		dca->dca_data = c;
53649300Shibler 		if (dca_hasfifo & (1 << unit)) {
53749300Shibler 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
53849300Shibler 				dca->dca_data = getc(&tp->t_outq);
53949300Shibler #ifdef DEBUG
54049300Shibler 			if (c > 16)
54149300Shibler 				fifoout[0]++;
54249300Shibler 			else
54349300Shibler 				fifoout[c]++;
54449300Shibler #endif
54549300Shibler 		}
54644318Shibler 	}
54741480Smckusick out:
54841480Smckusick 	splx(s);
54941480Smckusick }
55041480Smckusick 
55141480Smckusick /*
55241480Smckusick  * Stop output on a line.
55341480Smckusick  */
55441480Smckusick /*ARGSUSED*/
55541480Smckusick dcastop(tp, flag)
55641480Smckusick 	register struct tty *tp;
55741480Smckusick {
55841480Smckusick 	register int s;
55941480Smckusick 
56041480Smckusick 	s = spltty();
56141480Smckusick 	if (tp->t_state & TS_BUSY) {
56241480Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
56341480Smckusick 			tp->t_state |= TS_FLUSH;
56441480Smckusick 	}
56541480Smckusick 	splx(s);
56641480Smckusick }
56741480Smckusick 
56841480Smckusick dcamctl(dev, bits, how)
56941480Smckusick 	dev_t dev;
57041480Smckusick 	int bits, how;
57141480Smckusick {
57241480Smckusick 	register struct dcadevice *dca;
57341480Smckusick 	register int unit;
57441480Smckusick 	int s;
57541480Smckusick 
57641480Smckusick 	unit = UNIT(dev);
57741480Smckusick 	dca = dca_addr[unit];
57841480Smckusick 	s = spltty();
57941480Smckusick 	switch (how) {
58041480Smckusick 
58141480Smckusick 	case DMSET:
58241480Smckusick 		dca->dca_mcr = bits;
58341480Smckusick 		break;
58441480Smckusick 
58541480Smckusick 	case DMBIS:
58641480Smckusick 		dca->dca_mcr |= bits;
58741480Smckusick 		break;
58841480Smckusick 
58941480Smckusick 	case DMBIC:
59041480Smckusick 		dca->dca_mcr &= ~bits;
59141480Smckusick 		break;
59241480Smckusick 
59341480Smckusick 	case DMGET:
59441480Smckusick 		bits = dca->dca_msr;
59541480Smckusick 		break;
59641480Smckusick 	}
59741480Smckusick 	(void) splx(s);
59841480Smckusick 	return(bits);
59941480Smckusick }
60041480Smckusick 
60141480Smckusick /*
60241480Smckusick  * Following are all routines needed for DCA to act as console
60341480Smckusick  */
60445788Sbostic #include "../hp300/cons.h"
60541480Smckusick 
60641480Smckusick dcacnprobe(cp)
60741480Smckusick 	struct consdev *cp;
60841480Smckusick {
60949300Shibler 	int unit;
61041480Smckusick 
61149130Skarels 	/* locate the major number */
61249130Skarels 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
61349130Skarels 		if (cdevsw[dcamajor].d_open == dcaopen)
61449130Skarels 			break;
61549130Skarels 
61641480Smckusick 	/* XXX: ick */
61741480Smckusick 	unit = CONUNIT;
61849300Shibler 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
61941480Smckusick 
62041480Smckusick 	/* make sure hardware exists */
62141480Smckusick 	if (badaddr((short *)dca_addr[unit])) {
62241480Smckusick 		cp->cn_pri = CN_DEAD;
62341480Smckusick 		return;
62441480Smckusick 	}
62541480Smckusick 
62641480Smckusick 	/* initialize required fields */
62749130Skarels 	cp->cn_dev = makedev(dcamajor, unit);
62841480Smckusick 	cp->cn_tp = &dca_tty[unit];
62941480Smckusick 	switch (dca_addr[unit]->dca_irid) {
63041480Smckusick 	case DCAID0:
63141480Smckusick 	case DCAID1:
63241480Smckusick 		cp->cn_pri = CN_NORMAL;
63341480Smckusick 		break;
63441480Smckusick 	case DCAREMID0:
63541480Smckusick 	case DCAREMID1:
63641480Smckusick 		cp->cn_pri = CN_REMOTE;
63741480Smckusick 		break;
63841480Smckusick 	default:
63941480Smckusick 		cp->cn_pri = CN_DEAD;
64041480Smckusick 		break;
64141480Smckusick 	}
64249130Skarels 	/*
64349300Shibler 	 * If dcaconsole is initialized, raise our priority.
64449130Skarels 	 */
64549130Skarels 	if (dcaconsole == unit)
64649130Skarels 		cp->cn_pri = CN_REMOTE;
64749300Shibler #ifdef KGDB
64849130Skarels 	if (major(kgdb_dev) == 1)			/* XXX */
64949130Skarels 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
65049300Shibler #endif
65141480Smckusick }
65241480Smckusick 
65341480Smckusick dcacninit(cp)
65441480Smckusick 	struct consdev *cp;
65541480Smckusick {
65641480Smckusick 	int unit = UNIT(cp->cn_dev);
65741480Smckusick 
65849130Skarels 	dcainit(unit, dcadefaultrate);
65941480Smckusick 	dcaconsole = unit;
66049130Skarels 	dcaconsinit = 1;
66141480Smckusick }
66241480Smckusick 
66349130Skarels dcainit(unit, rate)
66449130Skarels 	int unit, rate;
66541480Smckusick {
66641480Smckusick 	register struct dcadevice *dca;
66749130Skarels 	int s;
66841480Smckusick 	short stat;
66941480Smckusick 
67041480Smckusick #ifdef lint
67141480Smckusick 	stat = unit; if (stat) return;
67241480Smckusick #endif
67341480Smckusick 	dca = dca_addr[unit];
67441480Smckusick 	s = splhigh();
67541480Smckusick 	dca->dca_irid = 0xFF;
67641480Smckusick 	DELAY(100);
67741480Smckusick 	dca->dca_ic = IC_IE;
67841480Smckusick 	dca->dca_cfcr = CFCR_DLAB;
67949130Skarels 	rate = ttspeedtab(rate, dcaspeedtab);
68041480Smckusick 	dca->dca_data = rate & 0xFF;
68141480Smckusick 	dca->dca_ier = rate >> 8;
68241480Smckusick 	dca->dca_cfcr = CFCR_8BITS;
68341480Smckusick 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
68449300Shibler 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
68541480Smckusick 	stat = dca->dca_iir;
68641480Smckusick 	splx(s);
68741480Smckusick }
68841480Smckusick 
68941480Smckusick dcacngetc(dev)
69041480Smckusick {
69141480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
69241480Smckusick 	short stat;
69341480Smckusick 	int c, s;
69441480Smckusick 
69541480Smckusick #ifdef lint
69641480Smckusick 	stat = dev; if (stat) return(0);
69741480Smckusick #endif
69841480Smckusick 	s = splhigh();
69941480Smckusick 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
70041480Smckusick 		;
70141480Smckusick 	c = dca->dca_data;
70241480Smckusick 	stat = dca->dca_iir;
70341480Smckusick 	splx(s);
70441480Smckusick 	return(c);
70541480Smckusick }
70641480Smckusick 
70741480Smckusick /*
70841480Smckusick  * Console kernel output character routine.
70941480Smckusick  */
71041480Smckusick dcacnputc(dev, c)
71141480Smckusick 	dev_t dev;
71241480Smckusick 	register int c;
71341480Smckusick {
71441480Smckusick 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
71541480Smckusick 	register int timo;
71641480Smckusick 	short stat;
71741480Smckusick 	int s = splhigh();
71841480Smckusick 
71941480Smckusick #ifdef lint
72041480Smckusick 	stat = dev; if (stat) return;
72141480Smckusick #endif
72249130Skarels #ifdef KGDB
72349130Skarels 	if (dev != kgdb_dev)
72449130Skarels #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