xref: /csrg-svn/sys/vax/uba/dhu.c (revision 23322)
1*23322Smckusick /*
2*23322Smckusick  * Copyright (c) 1982 Regents of the University of California.
3*23322Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*23322Smckusick  * specifies the terms and conditions for redistribution.
5*23322Smckusick  *
6*23322Smckusick  *	@(#)dhu.c	4.2 (Berkeley) 06/08/85
7*23322Smckusick  */
820976Smckusick 
920976Smckusick /*
1020976Smckusick  * based on	dh.c 6.3	84/03/15
1120976Smckusick  * and on	dmf.c	6.2	84/02/16
1220976Smckusick  *
1320976Smckusick  * Dave Johnson, Brown University Computer Science
1420976Smckusick  *	ddj%brown@csnet-relay
1520976Smckusick  */
1620976Smckusick 
1720976Smckusick #include "dhu.h"
1820976Smckusick #if NDHU > 0
1920976Smckusick /*
2020976Smckusick  * DHU-11 driver
2120976Smckusick  */
2220976Smckusick #include "../machine/pte.h"
2320976Smckusick 
2420976Smckusick #include "bk.h"
2520976Smckusick #include "param.h"
2620976Smckusick #include "conf.h"
2720976Smckusick #include "dir.h"
2820976Smckusick #include "user.h"
2920976Smckusick #include "proc.h"
3020976Smckusick #include "ioctl.h"
3120976Smckusick #include "tty.h"
3220976Smckusick #include "map.h"
3320976Smckusick #include "buf.h"
3420976Smckusick #include "vm.h"
3520976Smckusick #include "kernel.h"
3620976Smckusick #include "syslog.h"
3720976Smckusick 
3820976Smckusick #include "uba.h"
3920976Smckusick #include "ubareg.h"
4020976Smckusick #include "ubavar.h"
4120976Smckusick #include "dhureg.h"
4220976Smckusick 
4320976Smckusick #include "bkmac.h"
4420976Smckusick #include "clist.h"
4520976Smckusick #include "file.h"
4620976Smckusick #include "uio.h"
4720976Smckusick 
4820976Smckusick /*
4920976Smckusick  * Definition of the driver for the auto-configuration program.
5020976Smckusick  */
5120976Smckusick int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
5220976Smckusick struct	uba_device *dhuinfo[NDHU];
5320976Smckusick u_short dhustd[] = { 160440, 160500 };	/* some common addresses */
5420976Smckusick struct	uba_driver dhudriver =
5520976Smckusick 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
5620976Smckusick 
5720976Smckusick #define	NDHULINE 	(NDHU*16)
5820976Smckusick 
5920976Smckusick #define	UNIT(x)	(minor(x))
6020976Smckusick 
6120976Smckusick #ifndef PORTSELECTOR
6220976Smckusick #define ISPEED	B300
6320976Smckusick #define IFLAGS	(EVENP|ODDP|ECHO)
6420976Smckusick #else
6520976Smckusick #define ISPEED	B4800
6620976Smckusick #define IFLAGS	(EVENP|ODDP)
6720976Smckusick #endif
6820976Smckusick 
6920976Smckusick /*
7020976Smckusick  * default receive silo timeout value -- valid values are 2..255
7120976Smckusick  * number of ms. to delay between first char received and receive interrupt
7220976Smckusick  *
7320976Smckusick  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
7420976Smckusick  */
7520976Smckusick #define	DHU_DEF_TIMO	20
7620976Smckusick 
7720976Smckusick /*
7820976Smckusick  * Other values for silo timeout register defined here but not used:
7920976Smckusick  * receive interrupt only on modem control or silo alarm (3/4 full)
8020976Smckusick  */
8120976Smckusick #define DHU_POLL_TIMO	0
8220976Smckusick /*
8320976Smckusick  * receive interrupt immediately on receive character
8420976Smckusick  */
8520976Smckusick #define DHU_NO_TIMO	1
8620976Smckusick 
8720976Smckusick /*
8820976Smckusick  * Local variables for the driver
8920976Smckusick  */
9020976Smckusick /*
9120976Smckusick  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
9220976Smckusick  *	EXTA => 19200 baud
9320976Smckusick  *	EXTB => 2000 baud
9420976Smckusick  */
9520976Smckusick char	dhu_speeds[] =
9620976Smckusick 	{ 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 10, 11, 13, 14, 9 };
9720976Smckusick 
9820976Smckusick short	dhusoftCAR[NDHU];
9920976Smckusick 
10020976Smckusick struct	tty dhu_tty[NDHULINE];
10120976Smckusick int	ndhu = NDHULINE;
10220976Smckusick int	dhuact;				/* mask of active dhu's */
10320976Smckusick int	dhustart(), ttrstrt();
10420976Smckusick 
10520976Smckusick /*
10620976Smckusick  * The clist space is mapped by the driver onto each UNIBUS.
10720976Smckusick  * The UBACVT macro converts a clist space address for unibus uban
10820976Smckusick  * into an i/o space address for the DMA routine.
10920976Smckusick  */
11020976Smckusick int	dhu_ubinfo[NUBA];	/* info about allocated unibus map */
11120976Smckusick static int cbase[NUBA];		/* base address in unibus map */
11220976Smckusick #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
11320976Smckusick 
11420976Smckusick /*
11520976Smckusick  * Routine for configuration to force a dhu to interrupt.
11620976Smckusick  */
11720976Smckusick /*ARGSUSED*/
11820976Smckusick dhuprobe(reg)
11920976Smckusick 	caddr_t reg;
12020976Smckusick {
12120976Smckusick 	register int br, cvec;		/* these are ``value-result'' */
12220976Smckusick 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
12320976Smckusick 	int i;
12420976Smckusick 
12520976Smckusick #ifdef lint
12620976Smckusick 	br = 0; cvec = br; br = cvec;
12720976Smckusick 	if (ndhu == 0) ndhu = 1;
12820976Smckusick 	dhurint(0); dhuxint(0);
12920976Smckusick #endif
13020976Smckusick 	/*
13120976Smckusick 	 * The basic idea here is:
13220976Smckusick 	 *	do a self-test by setting the Master-Reset bit
13320976Smckusick 	 *	if this fails, then return
13420976Smckusick 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
13520976Smckusick 	 *	therefore ask for a  Received-Data-Available interrupt
13620976Smckusick 	 *	wait for it...
13720976Smckusick 	 *	reset the interrupt-enable bit and flush out the diag. codes
13820976Smckusick 	 */
13920976Smckusick 	dhuaddr->dhucsr = DHU_CS_MCLR;
14020976Smckusick 	for (i = 0; i < 1000; i++) {
14120976Smckusick 		DELAY(10000);
14220976Smckusick 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
14320976Smckusick 			break;
14420976Smckusick 	}
14520976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
14620976Smckusick 		return(0);
14720976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
14820976Smckusick 		return(0);
14920976Smckusick 	dhuaddr->dhucsr = DHU_CS_RIE;
15020976Smckusick 	DELAY(1000);
15120976Smckusick 	dhuaddr->dhucsr = 0;
15220976Smckusick 	while (dhuaddr->dhurbuf < 0)
15320976Smckusick 		/* void */;
15420976Smckusick 	return (sizeof(struct dhudevice));
15520976Smckusick }
15620976Smckusick 
15720976Smckusick /*
15820976Smckusick  * Routine called to attach a dhu.
15920976Smckusick  */
16020976Smckusick dhuattach(ui)
16120976Smckusick 	struct uba_device *ui;
16220976Smckusick {
16320976Smckusick 
16420976Smckusick 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
16520976Smckusick }
16620976Smckusick 
16720976Smckusick /*
16820976Smckusick  * Open a DHU11 line, mapping the clist onto the uba if this
16920976Smckusick  * is the first dhu on this uba.  Turn on this dhu if this is
17020976Smckusick  * the first use of it.
17120976Smckusick  */
17220976Smckusick /*ARGSUSED*/
17320976Smckusick dhuopen(dev, flag)
17420976Smckusick 	dev_t dev;
17520976Smckusick {
17620976Smckusick 	register struct tty *tp;
17720976Smckusick 	register int unit, dhu;
17820976Smckusick 	register struct dhudevice *addr;
17920976Smckusick 	register struct uba_device *ui;
18020976Smckusick 	int s;
18120976Smckusick 
18220976Smckusick 	unit = UNIT(dev);
18320976Smckusick 	dhu = unit >> 4;
18420976Smckusick 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
18520976Smckusick 		return (ENXIO);
18620976Smckusick 	tp = &dhu_tty[unit];
18720976Smckusick 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
18820976Smckusick 		return (EBUSY);
18920976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
19020976Smckusick 	tp->t_addr = (caddr_t)addr;
19120976Smckusick 	tp->t_oproc = dhustart;
19220976Smckusick 	/*
19320976Smckusick 	 * While setting up state for this uba and this dhu,
19420976Smckusick 	 * block uba resets which can clear the state.
19520976Smckusick 	 */
19620976Smckusick 	s = spl5();
19720976Smckusick 	if (dhu_ubinfo[ui->ui_ubanum] == 0) {
19820976Smckusick 		dhu_ubinfo[ui->ui_ubanum] =
19920976Smckusick 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
20020976Smckusick 			nclist*sizeof(struct cblock), 0);
20120976Smckusick 		cbase[ui->ui_ubanum] = dhu_ubinfo[ui->ui_ubanum]&0x3ffff;
20220976Smckusick 	}
20320976Smckusick 	if ((dhuact&(1<<dhu)) == 0) {
20420976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
20520976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
20620976Smckusick 		dhuact |= (1<<dhu);
20720976Smckusick 		/* anything else to configure whole board */
20820976Smckusick 	}
20920976Smckusick 	(void) splx(s);
21020976Smckusick 	/*
21120976Smckusick 	 * If this is first open, initialize tty state to default.
21220976Smckusick 	 */
21320976Smckusick 	if ((tp->t_state&TS_ISOPEN) == 0) {
21420976Smckusick 		ttychars(tp);
21520976Smckusick #ifndef PORTSELECTOR
21620976Smckusick 		if (tp->t_ispeed == 0) {
21720976Smckusick #else
21820976Smckusick 			tp->t_state |= TS_HUPCLS;
21920976Smckusick #endif PORTSELECTOR
22020976Smckusick 			tp->t_ispeed = ISPEED;
22120976Smckusick 			tp->t_ospeed = ISPEED;
22220976Smckusick 			tp->t_flags = IFLAGS;
22320976Smckusick #ifndef PORTSELECTOR
22420976Smckusick 		}
22520976Smckusick #endif PORTSELECTOR
22620976Smckusick 		tp->t_dev = dev;
22720976Smckusick 		dhuparam(unit);
22820976Smckusick 	}
22920976Smckusick 	/*
23020976Smckusick 	 * Wait for carrier, then process line discipline specific open.
23120976Smckusick 	 */
23220976Smckusick 	s = spl5();
23320976Smckusick 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
23420976Smckusick 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
23520976Smckusick 		tp->t_state |= TS_CARR_ON;
23620976Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
23720976Smckusick 		tp->t_state |= TS_WOPEN;
23820976Smckusick 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
23920976Smckusick 	}
24020976Smckusick 	(void) splx(s);
24120976Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
24220976Smckusick }
24320976Smckusick 
24420976Smckusick /*
24520976Smckusick  * Close a DHU11 line, turning off the modem control.
24620976Smckusick  */
24720976Smckusick /*ARGSUSED*/
24820976Smckusick dhuclose(dev, flag)
24920976Smckusick 	dev_t dev;
25020976Smckusick 	int flag;
25120976Smckusick {
25220976Smckusick 	register struct tty *tp;
25320976Smckusick 	register unit;
25420976Smckusick 
25520976Smckusick 	unit = UNIT(dev);
25620976Smckusick 	tp = &dhu_tty[unit];
25720976Smckusick 	(*linesw[tp->t_line].l_close)(tp);
25820976Smckusick 	(void) dhumctl(unit, DHU_BRK, DMBIC);
25920976Smckusick 	if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0)
26020976Smckusick #ifdef PORTSELECTOR
26120976Smckusick 	{
26220976Smckusick 		extern int wakeup();
26320976Smckusick 
26420976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
26520976Smckusick 		/* Hold DTR low for 0.5 seconds */
26620976Smckusick 		timeout(wakeup, (caddr_t) &tp->t_dev, hz/2);
26720976Smckusick 		sleep((caddr_t) &tp->t_dev, PZERO);
26820976Smckusick 	}
26920976Smckusick #else
27020976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
27120976Smckusick #endif PORTSELECTOR
27220976Smckusick 	ttyclose(tp);
27320976Smckusick }
27420976Smckusick 
27520976Smckusick dhuread(dev, uio)
27620976Smckusick 	dev_t dev;
27720976Smckusick 	struct uio *uio;
27820976Smckusick {
27920976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
28020976Smckusick 
28120976Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio));
28220976Smckusick }
28320976Smckusick 
28420976Smckusick dhuwrite(dev, uio)
28520976Smckusick 	dev_t dev;
28620976Smckusick 	struct uio *uio;
28720976Smckusick {
28820976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
28920976Smckusick 
29020976Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio));
29120976Smckusick }
29220976Smckusick 
29320976Smckusick /*
29420976Smckusick  * DHU11 receiver interrupt.
29520976Smckusick  */
29620976Smckusick dhurint(dhu)
29720976Smckusick 	int dhu;
29820976Smckusick {
29920976Smckusick 	register struct tty *tp;
30020976Smckusick 	register c;
30120976Smckusick 	register struct dhudevice *addr;
30220976Smckusick 	register struct tty *tp0;
30320976Smckusick 	register struct uba_device *ui;
30420976Smckusick 	register line;
30520976Smckusick 	int overrun = 0;
30620976Smckusick 
30720976Smckusick 	ui = dhuinfo[dhu];
30820976Smckusick 	if (ui == 0 || ui->ui_alive == 0)
30920976Smckusick 		return;
31020976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
31120976Smckusick 	tp0 = &dhu_tty[dhu<<4];
31220976Smckusick 	/*
31320976Smckusick 	 * Loop fetching characters from the silo for this
31420976Smckusick 	 * dhu until there are no more in the silo.
31520976Smckusick 	 */
31620976Smckusick 	while ((c = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
31720976Smckusick 		line = DHU_RX_LINE(c);
31820976Smckusick 		tp = tp0 + line;
31920976Smckusick 		if ((c & DHU_RB_STAT) == DHU_RB_STAT) {
32020976Smckusick 			/*
32120976Smckusick 			 * modem changed or diag info
32220976Smckusick 			 */
32320976Smckusick 			if (c & DHU_RB_DIAG) {
32420976Smckusick 				/* decode diagnostic messages */
32520976Smckusick 				continue;
32620976Smckusick 			}
32720976Smckusick 			if ((tp->t_state & TS_WOPEN) == 0 &&
32820976Smckusick 			    (tp->t_flags & MDMBUF)) {
32920976Smckusick 				if (c & DHU_ST_DCD) {
33020976Smckusick 					tp->t_state &= ~TS_TTSTOP;
33120976Smckusick 					ttstart(tp);
33220976Smckusick 				} else if ((tp->t_state & TS_TTSTOP) == 0) {
33320976Smckusick 					tp->t_state |= TS_TTSTOP;
33420976Smckusick 					dhustop(tp, 0);
33520976Smckusick 				}
33620976Smckusick 			} else if ((c & DHU_ST_DCD) == 0 &&
33720976Smckusick 				   (dhusoftCAR[dhu] & (1<<line)) == 0) {
33820976Smckusick 				if ((tp->t_state & TS_WOPEN) == 0 &&
33920976Smckusick 				    (tp->t_flags & NOHANG) == 0) {
34020976Smckusick 					gsignal(tp->t_pgrp, SIGHUP);
34120976Smckusick 					gsignal(tp->t_pgrp, SIGCONT);
34220976Smckusick 					(void) dhumctl((dhu<<4)|line,
34320976Smckusick 								DHU_OFF, DMSET);
34420976Smckusick 					ttyflush(tp, FREAD|FWRITE);
34520976Smckusick 				}
34620976Smckusick 				tp->t_state &= ~TS_CARR_ON;
34720976Smckusick 			} else {
34820976Smckusick 				if ((tp->t_state & TS_CARR_ON) == 0) {
34920976Smckusick 					tp->t_state |= TS_CARR_ON;
35020976Smckusick 					wakeup((caddr_t)&tp->t_rawq);
35120976Smckusick 				}
35220976Smckusick 			}
35320976Smckusick 			continue;
35420976Smckusick 		}
35520976Smckusick 		if ((tp->t_state&TS_ISOPEN) == 0) {
35620976Smckusick 			wakeup((caddr_t)&tp->t_rawq);
35720976Smckusick #ifdef PORTSELECTOR
35820976Smckusick 			if ((tp->t_state&TS_WOPEN) == 0)
35920976Smckusick #endif
36020976Smckusick 			continue;
36120976Smckusick 		}
36220976Smckusick 		if (c & DHU_RB_PE)
36320976Smckusick 			if ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
36420976Smckusick 			    (tp->t_flags&(EVENP|ODDP)) == ODDP)
36520976Smckusick 				continue;
36620976Smckusick 		if ((c & DHU_RB_DO) && overrun == 0) {
36720976Smckusick 			log(KERN_RECOV, "dhu%d: silo overflow\n", dhu);
36820976Smckusick 			overrun = 1;
36920976Smckusick 		}
37020976Smckusick 		if (c & DHU_RB_FE)
37120976Smckusick 			/*
37220976Smckusick 			 * At framing error (break) generate
37320976Smckusick 			 * a null (in raw mode, for getty), or a
37420976Smckusick 			 * interrupt (in cooked/cbreak mode).
37520976Smckusick 			 */
37620976Smckusick 			if (tp->t_flags&RAW)
37720976Smckusick 				c = 0;
37820976Smckusick 			else
37920976Smckusick 				c = tp->t_intrc;
38020976Smckusick #if NBK > 0
38120976Smckusick 		if (tp->t_line == NETLDISC) {
38220976Smckusick 			c &= 0x7f;
38320976Smckusick 			BKINPUT(c, tp);
38420976Smckusick 		} else
38520976Smckusick #endif
38620976Smckusick 			(*linesw[tp->t_line].l_rint)(c, tp);
38720976Smckusick 	}
38820976Smckusick }
38920976Smckusick 
39020976Smckusick /*
39120976Smckusick  * Ioctl for DHU11.
39220976Smckusick  */
39320976Smckusick /*ARGSUSED*/
39420976Smckusick dhuioctl(dev, cmd, data, flag)
39520976Smckusick 	caddr_t data;
39620976Smckusick {
39720976Smckusick 	register struct tty *tp;
39820976Smckusick 	register int unit = UNIT(dev);
39920976Smckusick 	register dhu = unit>>4;
40020976Smckusick 	register bit = (1<<(unit&0xf));
40120976Smckusick 	int error;
40220976Smckusick 
40320976Smckusick 	tp = &dhu_tty[unit];
40420976Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
40520976Smckusick 	if (error >= 0)
40620976Smckusick 		return (error);
40720976Smckusick 	error = ttioctl(tp, cmd, data, flag);
40820976Smckusick 	if (error >= 0) {
40920976Smckusick 		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET ||
41020976Smckusick 		    cmd == TIOCLBIC || cmd == TIOCLBIS)
41120976Smckusick 			dhuparam(unit);
41220976Smckusick 		return (error);
41320976Smckusick 	}
41420976Smckusick 
41520976Smckusick 	switch (cmd) {
41620976Smckusick 	case TIOCSBRK:
41720976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIS);
41820976Smckusick 		break;
41920976Smckusick 
42020976Smckusick 	case TIOCCBRK:
42120976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIC);
42220976Smckusick 		break;
42320976Smckusick 
42420976Smckusick 	case TIOCSDTR:
42520976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
42620976Smckusick 		break;
42720976Smckusick 
42820976Smckusick 	case TIOCCDTR:
42920976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
43020976Smckusick 		break;
43120976Smckusick 
43220976Smckusick 	case TIOCMSET:
43320976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
43420976Smckusick 		break;
43520976Smckusick 
43620976Smckusick 	case TIOCMBIS:
43720976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
43820976Smckusick 		break;
43920976Smckusick 
44020976Smckusick 	case TIOCMBIC:
44120976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
44220976Smckusick 		break;
44320976Smckusick 
44420976Smckusick 	case TIOCMGET:
44520976Smckusick 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
44620976Smckusick 		break;
44720976Smckusick 	default:
44820976Smckusick 		return (ENOTTY);
44920976Smckusick 	}
45020976Smckusick 	return (0);
45120976Smckusick }
45220976Smckusick 
45320976Smckusick dmtodhu(bits)
45420976Smckusick 	register int bits;
45520976Smckusick {
45620976Smckusick 	register int b = 0;
45720976Smckusick 
45820976Smckusick 	if (bits & DML_RTS) b |= DHU_RTS;
45920976Smckusick 	if (bits & DML_DTR) b |= DHU_DTR;
46020976Smckusick 	if (bits & DML_LE) b |= DHU_LE;
46120976Smckusick 	return(b);
46220976Smckusick }
46320976Smckusick 
46420976Smckusick dhutodm(bits)
46520976Smckusick 	register int bits;
46620976Smckusick {
46720976Smckusick 	register int b = 0;
46820976Smckusick 
46920976Smckusick 	if (bits & DHU_DSR) b |= DML_DSR;
47020976Smckusick 	if (bits & DHU_RNG) b |= DML_RNG;
47120976Smckusick 	if (bits & DHU_CAR) b |= DML_CAR;
47220976Smckusick 	if (bits & DHU_CTS) b |= DML_CTS;
47320976Smckusick 	if (bits & DHU_RTS) b |= DML_RTS;
47420976Smckusick 	if (bits & DHU_DTR) b |= DML_DTR;
47520976Smckusick 	if (bits & DHU_LE) b |= DML_LE;
47620976Smckusick 	return(b);
47720976Smckusick }
47820976Smckusick 
47920976Smckusick 
48020976Smckusick /*
48120976Smckusick  * Set parameters from open or stty into the DHU hardware
48220976Smckusick  * registers.
48320976Smckusick  */
48420976Smckusick dhuparam(unit)
48520976Smckusick 	register int unit;
48620976Smckusick {
48720976Smckusick 	register struct tty *tp;
48820976Smckusick 	register struct dhudevice *addr;
48920976Smckusick 	register int lpar;
49020976Smckusick 	int s;
49120976Smckusick 
49220976Smckusick 	tp = &dhu_tty[unit];
49320976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
49420976Smckusick 	/*
49520976Smckusick 	 * Block interrupts so parameters will be set
49620976Smckusick 	 * before the line interrupts.
49720976Smckusick 	 */
49820976Smckusick 	s = spl5();
49920976Smckusick 	if ((tp->t_ispeed) == 0) {
50020976Smckusick 		tp->t_state |= TS_HUPCLS;
50120976Smckusick 		(void)dhumctl(unit, DHU_OFF, DMSET);
50220976Smckusick 		splx(s);
50320976Smckusick 		return;
50420976Smckusick 	}
50520976Smckusick 	lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8);
50620976Smckusick 	if ((tp->t_ispeed) == B134)
50720976Smckusick 		lpar |= DHU_LP_BITS6|DHU_LP_PENABLE;
50820976Smckusick 	else if (tp->t_flags & (RAW|LITOUT))
50920976Smckusick 		lpar |= DHU_LP_BITS8;
51020976Smckusick 	else
51120976Smckusick 		lpar |= DHU_LP_BITS7|DHU_LP_PENABLE;
51220976Smckusick 	if (tp->t_flags&EVENP)
51320976Smckusick 		lpar |= DHU_LP_EPAR;
51420976Smckusick 	if ((tp->t_ospeed) == B110)
51520976Smckusick 		lpar |= DHU_LP_TWOSB;
51620976Smckusick 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
51720976Smckusick 	addr->dhulpr = lpar;
51820976Smckusick 	splx(s);
51920976Smckusick }
52020976Smckusick 
52120976Smckusick /*
52220976Smckusick  * DHU11 transmitter interrupt.
52320976Smckusick  * Restart each line which used to be active but has
52420976Smckusick  * terminated transmission since the last interrupt.
52520976Smckusick  */
52620976Smckusick dhuxint(dhu)
52720976Smckusick 	int dhu;
52820976Smckusick {
52920976Smckusick 	register struct tty *tp;
53020976Smckusick 	register struct dhudevice *addr;
53120976Smckusick 	register struct tty *tp0;
53220976Smckusick 	register struct uba_device *ui;
53320976Smckusick 	register int line, t;
53420976Smckusick 	u_short cntr;
53520976Smckusick 
53620976Smckusick 	ui = dhuinfo[dhu];
53720976Smckusick 	tp0 = &dhu_tty[dhu<<4];
53820976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
53920976Smckusick 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
54020976Smckusick 		line = DHU_TX_LINE(t);
54120976Smckusick 		tp = tp0 + line;
54220976Smckusick 		tp->t_state &= ~TS_BUSY;
54320976Smckusick 		if (t & DHU_CSH_NXM) {
54420976Smckusick 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
54520976Smckusick 			/* SHOULD RESTART OR SOMETHING... */
54620976Smckusick 		}
54720976Smckusick 		if (tp->t_state&TS_FLUSH)
54820976Smckusick 			tp->t_state &= ~TS_FLUSH;
54920976Smckusick 		else {
55020976Smckusick 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
55120976Smckusick 			/*
55220976Smckusick 			 * Do arithmetic in a short to make up
55320976Smckusick 			 * for lost 16&17 bits.
55420976Smckusick 			 */
55520976Smckusick 			cntr = addr->dhubar1 -
55620976Smckusick 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
55720976Smckusick 			ndflush(&tp->t_outq, (int)cntr);
55820976Smckusick 		}
55920976Smckusick 		if (tp->t_line)
56020976Smckusick 			(*linesw[tp->t_line].l_start)(tp);
56120976Smckusick 		else
56220976Smckusick 			dhustart(tp);
56320976Smckusick 	}
56420976Smckusick }
56520976Smckusick 
56620976Smckusick /*
56720976Smckusick  * Start (restart) transmission on the given DHU11 line.
56820976Smckusick  */
56920976Smckusick dhustart(tp)
57020976Smckusick 	register struct tty *tp;
57120976Smckusick {
57220976Smckusick 	register struct dhudevice *addr;
57320976Smckusick 	register int car, dhu, unit, nch;
57420976Smckusick 	int s;
57520976Smckusick 
57620976Smckusick 	unit = minor(tp->t_dev);
57720976Smckusick 	dhu = unit >> 4;
57820976Smckusick 	unit &= 0xf;
57920976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
58020976Smckusick 
58120976Smckusick 	/*
58220976Smckusick 	 * Must hold interrupts in following code to prevent
58320976Smckusick 	 * state of the tp from changing.
58420976Smckusick 	 */
58520976Smckusick 	s = spl5();
58620976Smckusick 	/*
58720976Smckusick 	 * If it's currently active, or delaying, no need to do anything.
58820976Smckusick 	 */
58920976Smckusick 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
59020976Smckusick 		goto out;
59120976Smckusick 	/*
59220976Smckusick 	 * If there are sleepers, and output has drained below low
59320976Smckusick 	 * water mark, wake up the sleepers..
59420976Smckusick 	 */
59520976Smckusick 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
59620976Smckusick 		if (tp->t_state&TS_ASLEEP) {
59720976Smckusick 			tp->t_state &= ~TS_ASLEEP;
59820976Smckusick 			wakeup((caddr_t)&tp->t_outq);
59920976Smckusick 		}
60020976Smckusick 		if (tp->t_wsel) {
60120976Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
60220976Smckusick 			tp->t_wsel = 0;
60320976Smckusick 			tp->t_state &= ~TS_WCOLL;
60420976Smckusick 		}
60520976Smckusick 	}
60620976Smckusick 	/*
60720976Smckusick 	 * Now restart transmission unless the output queue is
60820976Smckusick 	 * empty.
60920976Smckusick 	 */
61020976Smckusick 	if (tp->t_outq.c_cc == 0)
61120976Smckusick 		goto out;
61220976Smckusick 	if (tp->t_flags & (RAW|LITOUT))
61320976Smckusick 		nch = ndqb(&tp->t_outq, 0);
61420976Smckusick 	else {
61520976Smckusick 		nch = ndqb(&tp->t_outq, 0200);
61620976Smckusick 		/*
61720976Smckusick 		 * If first thing on queue is a delay process it.
61820976Smckusick 		 */
61920976Smckusick 		if (nch == 0) {
62020976Smckusick 			nch = getc(&tp->t_outq);
62120976Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
62220976Smckusick 			tp->t_state |= TS_TIMEOUT;
62320976Smckusick 			goto out;
62420976Smckusick 		}
62520976Smckusick 	}
62620976Smckusick 	/*
62720976Smckusick 	 * If characters to transmit, restart transmission.
62820976Smckusick 	 */
62920976Smckusick 	if (nch) {
63020976Smckusick 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
63120976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
63220976Smckusick 		addr->dhulcr &= ~DHU_LC_TXABORT;
63320976Smckusick 		addr->dhubcr = nch;
63420976Smckusick 		addr->dhubar1 = car;
63520976Smckusick 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
63620976Smckusick 					DHU_BA2_DMAGO;
63720976Smckusick 		tp->t_state |= TS_BUSY;
63820976Smckusick 	}
63920976Smckusick out:
64020976Smckusick 	splx(s);
64120976Smckusick }
64220976Smckusick 
64320976Smckusick /*
64420976Smckusick  * Stop output on a line, e.g. for ^S/^Q or output flush.
64520976Smckusick  */
64620976Smckusick /*ARGSUSED*/
64720976Smckusick dhustop(tp, flag)
64820976Smckusick 	register struct tty *tp;
64920976Smckusick {
65020976Smckusick 	register struct dhudevice *addr;
65120976Smckusick 	register int unit, s;
65220976Smckusick 
65320976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
65420976Smckusick 	/*
65520976Smckusick 	 * Block input/output interrupts while messing with state.
65620976Smckusick 	 */
65720976Smckusick 	s = spl5();
65820976Smckusick 	if (tp->t_state & TS_BUSY) {
65920976Smckusick 		/*
66020976Smckusick 		 * Device is transmitting; stop output
66120976Smckusick 		 * by selecting the line and setting the
66220976Smckusick 		 * abort xmit bit.  We will get an xmit interrupt,
66320976Smckusick 		 * where we will figure out where to continue the
66420976Smckusick 		 * next time the transmitter is enabled.  If
66520976Smckusick 		 * TS_FLUSH is set, the outq will be flushed.
66620976Smckusick 		 * In either case, dhustart will clear the TXABORT bit.
66720976Smckusick 		 */
66820976Smckusick 		unit = minor(tp->t_dev);
66920976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
67020976Smckusick 		addr->dhulcr |= DHU_LC_TXABORT;
67120976Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
67220976Smckusick 			tp->t_state |= TS_FLUSH;
67320976Smckusick 	}
67420976Smckusick 	(void) splx(s);
67520976Smckusick }
67620976Smckusick 
67720976Smckusick /*
67820976Smckusick  * DHU11 modem control
67920976Smckusick  */
68020976Smckusick dhumctl(dev, bits, how)
68120976Smckusick 	dev_t dev;
68220976Smckusick 	int bits, how;
68320976Smckusick {
68420976Smckusick 	register struct dhudevice *dhuaddr;
68520976Smckusick 	register int unit, mbits, lcr;
68620976Smckusick 	int s;
68720976Smckusick 
68820976Smckusick 	unit = UNIT(dev);
68920976Smckusick 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
69020976Smckusick 	unit &= 0xf;
69120976Smckusick 	s = spl5();
69220976Smckusick 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
69320976Smckusick 	/*
69420976Smckusick 	 * combine byte from stat register (read only, bits 16..23)
69520976Smckusick 	 * with lcr register (read write, bits 0..15).
69620976Smckusick 	 */
69720976Smckusick 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
69820976Smckusick 	switch (how) {
69920976Smckusick 	case DMSET:
70020976Smckusick 		mbits = (mbits & 0xff0000) | bits;
70120976Smckusick 		break;
70220976Smckusick 
70320976Smckusick 	case DMBIS:
70420976Smckusick 		mbits |= bits;
70520976Smckusick 		break;
70620976Smckusick 
70720976Smckusick 	case DMBIC:
70820976Smckusick 		mbits &= ~bits;
70920976Smckusick 		break;
71020976Smckusick 
71120976Smckusick 	case DMGET:
71220976Smckusick 		(void) splx(s);
71320976Smckusick 		return(mbits);
71420976Smckusick 	}
71520976Smckusick 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
71620976Smckusick 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
71720976Smckusick 	(void) splx(s);
71820976Smckusick 	return(mbits);
71920976Smckusick }
72020976Smckusick 
72120976Smckusick /*
72220976Smckusick  * Reset state of driver if UBA reset was necessary.
72320976Smckusick  * Reset the line and modem control registers.
72420976Smckusick  * restart transmitters.
72520976Smckusick  */
72620976Smckusick dhureset(uban)
72720976Smckusick 	int uban;
72820976Smckusick {
72920976Smckusick 	register int dhu, unit;
73020976Smckusick 	register struct tty *tp;
73120976Smckusick 	register struct uba_device *ui;
73220976Smckusick 	register struct dhudevice *addr;
73320976Smckusick 	int i;
73420976Smckusick 	register int s;
73520976Smckusick 
73620976Smckusick 	if (dhu_ubinfo[uban] == 0)
73720976Smckusick 		return;
73820976Smckusick 	dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
73920976Smckusick 				    nclist*sizeof (struct cblock), 0);
74020976Smckusick 	cbase[uban] = dhu_ubinfo[uban]&0x3ffff;
74120976Smckusick 	for (dhu = 0; dhu < NDHU; dhu++) {
74220976Smckusick 		ui = dhuinfo[dhu];
74320976Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
74420976Smckusick 			continue;
74520976Smckusick 		printf(" dhu%d", dhu);
74620976Smckusick 		addr = (struct dhudevice *)ui->ui_addr;
74720976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
74820976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
74920976Smckusick 		unit = dhu * 16;
75020976Smckusick 		for (i = 0; i < 16; i++) {
75120976Smckusick 			tp = &dhu_tty[unit];
75220976Smckusick 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
75320976Smckusick 				dhuparam(unit);
75420976Smckusick 				(void)dhumctl(unit, DHU_ON, DMSET);
75520976Smckusick 				tp->t_state &= ~TS_BUSY;
75620976Smckusick 				dhustart(tp);
75720976Smckusick 			}
75820976Smckusick 			unit++;
75920976Smckusick 		}
76020976Smckusick 	}
76120976Smckusick }
76220976Smckusick #endif
763