xref: /csrg-svn/sys/vax/uba/dhu.c (revision 37606)
123322Smckusick /*
229211Smckusick  * Copyright (c) 1985, 1986 Regents of the University of California.
323322Smckusick  * All rights reserved.  The Berkeley software License Agreement
423322Smckusick  * specifies the terms and conditions for redistribution.
523322Smckusick  *
6*37606Smarc  *	@(#)dhu.c	7.6 (Berkeley) 05/01/89
723322Smckusick  */
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  */
2237514Smckusick #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"
32*37606Smarc #include "ttydefaults.h"
3320976Smckusick #include "map.h"
3420976Smckusick #include "buf.h"
3520976Smckusick #include "vm.h"
3620976Smckusick #include "kernel.h"
3720976Smckusick #include "syslog.h"
3820976Smckusick 
3920976Smckusick #include "uba.h"
4020976Smckusick #include "ubareg.h"
4120976Smckusick #include "ubavar.h"
4220976Smckusick #include "dhureg.h"
4320976Smckusick 
4420976Smckusick #include "bkmac.h"
4520976Smckusick #include "clist.h"
4620976Smckusick #include "file.h"
4720976Smckusick #include "uio.h"
4820976Smckusick 
4920976Smckusick /*
5020976Smckusick  * Definition of the driver for the auto-configuration program.
5120976Smckusick  */
5220976Smckusick int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
5320976Smckusick struct	uba_device *dhuinfo[NDHU];
5425519Stef u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
5520976Smckusick struct	uba_driver dhudriver =
5620976Smckusick 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
5720976Smckusick 
5820976Smckusick #define	NDHULINE 	(NDHU*16)
5920976Smckusick 
6020976Smckusick #define	UNIT(x)	(minor(x))
6120976Smckusick 
6220976Smckusick #ifndef PORTSELECTOR
63*37606Smarc #define SPEED	TTYDEF_SPEED
64*37606Smarc #define LFLAG	TTYDEF_LFLAG
6520976Smckusick #else
66*37606Smarc #define SPEED	B4800
67*37606Smarc #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
6820976Smckusick #endif
6920976Smckusick 
7020976Smckusick /*
7120976Smckusick  * default receive silo timeout value -- valid values are 2..255
7220976Smckusick  * number of ms. to delay between first char received and receive interrupt
7320976Smckusick  *
7420976Smckusick  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
7520976Smckusick  */
7620976Smckusick #define	DHU_DEF_TIMO	20
7720976Smckusick 
7820976Smckusick /*
7920976Smckusick  * Other values for silo timeout register defined here but not used:
8020976Smckusick  * receive interrupt only on modem control or silo alarm (3/4 full)
8120976Smckusick  */
8220976Smckusick #define DHU_POLL_TIMO	0
8320976Smckusick /*
8420976Smckusick  * receive interrupt immediately on receive character
8520976Smckusick  */
8620976Smckusick #define DHU_NO_TIMO	1
8720976Smckusick 
8820976Smckusick /*
8920976Smckusick  * Local variables for the driver
9020976Smckusick  */
9120976Smckusick /*
9220976Smckusick  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
9320976Smckusick  *	EXTA => 19200 baud
9420976Smckusick  *	EXTB => 2000 baud
9520976Smckusick  */
96*37606Smarc struct speedtab dhuspeedtab[] = {
97*37606Smarc 	19200,	14,
98*37606Smarc 	9600,	13,
99*37606Smarc 	4800,	11,
100*37606Smarc 	2400,	10,
101*37606Smarc 	2000,	9,
102*37606Smarc 	1800,	8,
103*37606Smarc 	1200,	7,
104*37606Smarc 	600,	6,
105*37606Smarc 	300,	5,
106*37606Smarc 	150,	4,
107*37606Smarc 	134,	3,
108*37606Smarc 	110,	2,
109*37606Smarc 	75,	1,
110*37606Smarc 	0,	0,
111*37606Smarc 	-1,	-1,
112*37606Smarc };
11320976Smckusick 
11420976Smckusick short	dhusoftCAR[NDHU];
11520976Smckusick 
11620976Smckusick struct	tty dhu_tty[NDHULINE];
11720976Smckusick int	ndhu = NDHULINE;
11820976Smckusick int	dhuact;				/* mask of active dhu's */
11920976Smckusick int	dhustart(), ttrstrt();
12020976Smckusick 
12120976Smckusick /*
12230322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
12330322Skarels  * The identity of the board which allocated resources is recorded,
12430322Skarels  * so the process may be repeated after UNIBUS resets.
12520976Smckusick  * The UBACVT macro converts a clist space address for unibus uban
12620976Smckusick  * into an i/o space address for the DMA routine.
12720976Smckusick  */
12830322Skarels int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
12930322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
13020976Smckusick #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
13120976Smckusick 
13220976Smckusick /*
13320976Smckusick  * Routine for configuration to force a dhu to interrupt.
13420976Smckusick  */
13520976Smckusick /*ARGSUSED*/
13620976Smckusick dhuprobe(reg)
13720976Smckusick 	caddr_t reg;
13820976Smckusick {
13920976Smckusick 	register int br, cvec;		/* these are ``value-result'' */
14020976Smckusick 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
14120976Smckusick 	int i;
14220976Smckusick 
14320976Smckusick #ifdef lint
14420976Smckusick 	br = 0; cvec = br; br = cvec;
14520976Smckusick 	if (ndhu == 0) ndhu = 1;
14620976Smckusick 	dhurint(0); dhuxint(0);
14720976Smckusick #endif
14820976Smckusick 	/*
14920976Smckusick 	 * The basic idea here is:
15020976Smckusick 	 *	do a self-test by setting the Master-Reset bit
15120976Smckusick 	 *	if this fails, then return
15220976Smckusick 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
15320976Smckusick 	 *	therefore ask for a  Received-Data-Available interrupt
15420976Smckusick 	 *	wait for it...
15520976Smckusick 	 *	reset the interrupt-enable bit and flush out the diag. codes
15620976Smckusick 	 */
15720976Smckusick 	dhuaddr->dhucsr = DHU_CS_MCLR;
15820976Smckusick 	for (i = 0; i < 1000; i++) {
15920976Smckusick 		DELAY(10000);
16020976Smckusick 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
16120976Smckusick 			break;
16220976Smckusick 	}
16320976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
16420976Smckusick 		return(0);
16520976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
16620976Smckusick 		return(0);
16720976Smckusick 	dhuaddr->dhucsr = DHU_CS_RIE;
16820976Smckusick 	DELAY(1000);
16920976Smckusick 	dhuaddr->dhucsr = 0;
17020976Smckusick 	while (dhuaddr->dhurbuf < 0)
17120976Smckusick 		/* void */;
17220976Smckusick 	return (sizeof(struct dhudevice));
17320976Smckusick }
17420976Smckusick 
17520976Smckusick /*
17620976Smckusick  * Routine called to attach a dhu.
17720976Smckusick  */
17820976Smckusick dhuattach(ui)
17920976Smckusick 	struct uba_device *ui;
18020976Smckusick {
18120976Smckusick 
18220976Smckusick 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
18326220Skarels 	cbase[ui->ui_ubanum] = -1;
18436610Sbostic 	dhu_uballoc[ui->ui_ubanum] = -1;
18520976Smckusick }
18620976Smckusick 
18720976Smckusick /*
18820976Smckusick  * Open a DHU11 line, mapping the clist onto the uba if this
18920976Smckusick  * is the first dhu on this uba.  Turn on this dhu if this is
19020976Smckusick  * the first use of it.
19120976Smckusick  */
19220976Smckusick /*ARGSUSED*/
19320976Smckusick dhuopen(dev, flag)
19420976Smckusick 	dev_t dev;
19520976Smckusick {
19620976Smckusick 	register struct tty *tp;
19720976Smckusick 	register int unit, dhu;
19820976Smckusick 	register struct dhudevice *addr;
19920976Smckusick 	register struct uba_device *ui;
20020976Smckusick 	int s;
201*37606Smarc 	extern dhuparam();
20220976Smckusick 
20320976Smckusick 	unit = UNIT(dev);
20420976Smckusick 	dhu = unit >> 4;
20520976Smckusick 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
20620976Smckusick 		return (ENXIO);
20720976Smckusick 	tp = &dhu_tty[unit];
20820976Smckusick 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
20920976Smckusick 		return (EBUSY);
21020976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
21120976Smckusick 	tp->t_addr = (caddr_t)addr;
21220976Smckusick 	tp->t_oproc = dhustart;
213*37606Smarc 	tp->t_param = dhuparam;
21420976Smckusick 	/*
21520976Smckusick 	 * While setting up state for this uba and this dhu,
21620976Smckusick 	 * block uba resets which can clear the state.
21720976Smckusick 	 */
21820976Smckusick 	s = spl5();
21926220Skarels 	if (cbase[ui->ui_ubanum] == -1) {
22030322Skarels 		dhu_uballoc[ui->ui_ubanum] = dhu;
22130322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22230322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22320976Smckusick 	}
22420976Smckusick 	if ((dhuact&(1<<dhu)) == 0) {
22520976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
22620976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
22720976Smckusick 		dhuact |= (1<<dhu);
22820976Smckusick 		/* anything else to configure whole board */
22920976Smckusick 	}
23020976Smckusick 	(void) splx(s);
23120976Smckusick 	/*
23220976Smckusick 	 * If this is first open, initialize tty state to default.
23320976Smckusick 	 */
23420976Smckusick 	if ((tp->t_state&TS_ISOPEN) == 0) {
23520976Smckusick 		ttychars(tp);
23620976Smckusick #ifndef PORTSELECTOR
237*37606Smarc 		if (tp->t_ospeed == 0) {
238*37606Smarc #endif
239*37606Smarc 			tp->t_ispeed = SPEED;
240*37606Smarc 			tp->t_ospeed = SPEED;
241*37606Smarc 			ttsetwater(tp);
242*37606Smarc 			tp->t_iflag = TTYDEF_IFLAG;
243*37606Smarc 			tp->t_oflag = TTYDEF_OFLAG;
244*37606Smarc 			tp->t_lflag = LFLAG;
245*37606Smarc 			tp->t_cflag = TTYDEF_CFLAG;
246*37606Smarc #ifdef PORTSELECTOR
247*37606Smarc 			tp->t_cflag |= HUPCL;
248*37606Smarc #else
24920976Smckusick 		}
250*37606Smarc #endif
25120976Smckusick 		tp->t_dev = dev;
252*37606Smarc 		dhuparam(tp, &tp->t_termios);
25320976Smckusick 	}
25420976Smckusick 	/*
25520976Smckusick 	 * Wait for carrier, then process line discipline specific open.
25620976Smckusick 	 */
257*37606Smarc 	s = spltty();
25820976Smckusick 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
25920976Smckusick 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
26020976Smckusick 		tp->t_state |= TS_CARR_ON;
26120976Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
26220976Smckusick 		tp->t_state |= TS_WOPEN;
26320976Smckusick 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
26420976Smckusick 	}
26520976Smckusick 	(void) splx(s);
26620976Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
26720976Smckusick }
26820976Smckusick 
26920976Smckusick /*
27020976Smckusick  * Close a DHU11 line, turning off the modem control.
27120976Smckusick  */
27220976Smckusick /*ARGSUSED*/
27320976Smckusick dhuclose(dev, flag)
27420976Smckusick 	dev_t dev;
27520976Smckusick 	int flag;
27620976Smckusick {
27720976Smckusick 	register struct tty *tp;
27820976Smckusick 	register unit;
27920976Smckusick 
28020976Smckusick 	unit = UNIT(dev);
28120976Smckusick 	tp = &dhu_tty[unit];
28220976Smckusick 	(*linesw[tp->t_line].l_close)(tp);
28320976Smckusick 	(void) dhumctl(unit, DHU_BRK, DMBIC);
284*37606Smarc 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
285*37606Smarc 	    (tp->t_state&TS_ISOPEN)==0)
28620976Smckusick #ifdef PORTSELECTOR
28720976Smckusick 	{
28820976Smckusick 		extern int wakeup();
28920976Smckusick 
29020976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29120976Smckusick 		/* Hold DTR low for 0.5 seconds */
29220976Smckusick 		timeout(wakeup, (caddr_t) &tp->t_dev, hz/2);
29320976Smckusick 		sleep((caddr_t) &tp->t_dev, PZERO);
29420976Smckusick 	}
29520976Smckusick #else
29620976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29720976Smckusick #endif PORTSELECTOR
29820976Smckusick 	ttyclose(tp);
29920976Smckusick }
30020976Smckusick 
30120976Smckusick dhuread(dev, uio)
30220976Smckusick 	dev_t dev;
30320976Smckusick 	struct uio *uio;
30420976Smckusick {
30520976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
30620976Smckusick 
30720976Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio));
30820976Smckusick }
30920976Smckusick 
31020976Smckusick dhuwrite(dev, uio)
31120976Smckusick 	dev_t dev;
31220976Smckusick 	struct uio *uio;
31320976Smckusick {
31420976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
31520976Smckusick 
31620976Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio));
31720976Smckusick }
31820976Smckusick 
31920976Smckusick /*
32020976Smckusick  * DHU11 receiver interrupt.
32120976Smckusick  */
32220976Smckusick dhurint(dhu)
32320976Smckusick 	int dhu;
32420976Smckusick {
32520976Smckusick 	register struct tty *tp;
326*37606Smarc 	register creg, c;
32720976Smckusick 	register struct dhudevice *addr;
32820976Smckusick 	register struct tty *tp0;
32920976Smckusick 	register struct uba_device *ui;
33020976Smckusick 	register line;
33120976Smckusick 	int overrun = 0;
33220976Smckusick 
33335401Stef #ifdef QBA
334*37606Smarc 	(void) spltty();
33527256Skridle #endif
33620976Smckusick 	ui = dhuinfo[dhu];
33720976Smckusick 	if (ui == 0 || ui->ui_alive == 0)
33820976Smckusick 		return;
33920976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
34020976Smckusick 	tp0 = &dhu_tty[dhu<<4];
34120976Smckusick 	/*
34220976Smckusick 	 * Loop fetching characters from the silo for this
34320976Smckusick 	 * dhu until there are no more in the silo.
34420976Smckusick 	 */
345*37606Smarc 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
346*37606Smarc 		line = DHU_RX_LINE(creg);
34720976Smckusick 		tp = tp0 + line;
348*37606Smarc 		c = creg & 0xff;
349*37606Smarc 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
35020976Smckusick 			/*
35120976Smckusick 			 * modem changed or diag info
35220976Smckusick 			 */
353*37606Smarc 			if (creg & DHU_RB_DIAG) {
35420976Smckusick 				/* decode diagnostic messages */
35520976Smckusick 				continue;
35620976Smckusick 			}
357*37606Smarc 			if (creg & DHU_ST_DCD)
35825395Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
35925395Skarels 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
36025395Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36125395Skarels 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
36220976Smckusick 			continue;
36320976Smckusick 		}
36420976Smckusick 		if ((tp->t_state&TS_ISOPEN) == 0) {
36520976Smckusick 			wakeup((caddr_t)&tp->t_rawq);
36620976Smckusick #ifdef PORTSELECTOR
36720976Smckusick 			if ((tp->t_state&TS_WOPEN) == 0)
36820976Smckusick #endif
36925395Skarels 				continue;
37020976Smckusick 		}
371*37606Smarc #ifdef COMPAT_43
372*37606Smarc 		if (tp->t_line != POSXDISC) {
373*37606Smarc 			if (creg & DHU_RB_PE)
374*37606Smarc 				if ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
375*37606Smarc 				    (tp->t_flags&(EVENP|ODDP)) == ODDP)
376*37606Smarc 					continue;
377*37606Smarc 			if ((creg & DHU_RB_DO) && overrun == 0) {
378*37606Smarc 				log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
379*37606Smarc 				overrun = 1;
380*37606Smarc 			}
381*37606Smarc 			if (creg & DHU_RB_FE)
382*37606Smarc 				/*
383*37606Smarc 				 * At framing error (break) generate
384*37606Smarc 				 * a null (in raw mode, for getty), or a
385*37606Smarc 				 * interrupt (in cooked/cbreak mode).
386*37606Smarc 				 */
387*37606Smarc 				if (tp->t_flags&RAW)
388*37606Smarc 					c = 0;
389*37606Smarc 				else
390*37606Smarc 					c = tp->t_intrc;
391*37606Smarc 		} else {
392*37606Smarc #endif /*COMPAT_43*/
393*37606Smarc 			if (creg & DHU_RB_PE)
394*37606Smarc 				c |= TTY_PE;
395*37606Smarc 			if (creg & DHU_RB_DO && overrun == 0) {
396*37606Smarc 				log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
397*37606Smarc 				overrun = 1;
398*37606Smarc 			}
399*37606Smarc 			if (creg & DHU_RB_FE)
400*37606Smarc 				c |= TTY_FE;
401*37606Smarc #ifdef COMPAT_43
40220976Smckusick 		}
403*37606Smarc #endif
404*37606Smarc 
40520976Smckusick #if NBK > 0
40620976Smckusick 		if (tp->t_line == NETLDISC) {
40720976Smckusick 			c &= 0x7f;
40820976Smckusick 			BKINPUT(c, tp);
40920976Smckusick 		} else
41020976Smckusick #endif
41120976Smckusick 			(*linesw[tp->t_line].l_rint)(c, tp);
41220976Smckusick 	}
41320976Smckusick }
41420976Smckusick 
41520976Smckusick /*
41620976Smckusick  * Ioctl for DHU11.
41720976Smckusick  */
41820976Smckusick /*ARGSUSED*/
41920976Smckusick dhuioctl(dev, cmd, data, flag)
42020976Smckusick 	caddr_t data;
42120976Smckusick {
42220976Smckusick 	register struct tty *tp;
42320976Smckusick 	register int unit = UNIT(dev);
42420976Smckusick 	int error;
42520976Smckusick 
42620976Smckusick 	tp = &dhu_tty[unit];
42720976Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
42820976Smckusick 	if (error >= 0)
42920976Smckusick 		return (error);
43020976Smckusick 	error = ttioctl(tp, cmd, data, flag);
431*37606Smarc 	if (error >= 0)
43220976Smckusick 		return (error);
43320976Smckusick 
43420976Smckusick 	switch (cmd) {
43520976Smckusick 	case TIOCSBRK:
43620976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIS);
43720976Smckusick 		break;
43820976Smckusick 
43920976Smckusick 	case TIOCCBRK:
44020976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIC);
44120976Smckusick 		break;
44220976Smckusick 
44320976Smckusick 	case TIOCSDTR:
44420976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
44520976Smckusick 		break;
44620976Smckusick 
44720976Smckusick 	case TIOCCDTR:
44820976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
44920976Smckusick 		break;
45020976Smckusick 
45120976Smckusick 	case TIOCMSET:
45220976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
45320976Smckusick 		break;
45420976Smckusick 
45520976Smckusick 	case TIOCMBIS:
45620976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
45720976Smckusick 		break;
45820976Smckusick 
45920976Smckusick 	case TIOCMBIC:
46020976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
46120976Smckusick 		break;
46220976Smckusick 
46320976Smckusick 	case TIOCMGET:
46420976Smckusick 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
46520976Smckusick 		break;
46620976Smckusick 	default:
46720976Smckusick 		return (ENOTTY);
46820976Smckusick 	}
46920976Smckusick 	return (0);
47020976Smckusick }
47120976Smckusick 
47220976Smckusick dmtodhu(bits)
47320976Smckusick 	register int bits;
47420976Smckusick {
47520976Smckusick 	register int b = 0;
47620976Smckusick 
47720976Smckusick 	if (bits & DML_RTS) b |= DHU_RTS;
47820976Smckusick 	if (bits & DML_DTR) b |= DHU_DTR;
47920976Smckusick 	if (bits & DML_LE) b |= DHU_LE;
48020976Smckusick 	return(b);
48120976Smckusick }
48220976Smckusick 
48320976Smckusick dhutodm(bits)
48420976Smckusick 	register int bits;
48520976Smckusick {
48620976Smckusick 	register int b = 0;
48720976Smckusick 
48820976Smckusick 	if (bits & DHU_DSR) b |= DML_DSR;
48920976Smckusick 	if (bits & DHU_RNG) b |= DML_RNG;
49020976Smckusick 	if (bits & DHU_CAR) b |= DML_CAR;
49120976Smckusick 	if (bits & DHU_CTS) b |= DML_CTS;
49220976Smckusick 	if (bits & DHU_RTS) b |= DML_RTS;
49320976Smckusick 	if (bits & DHU_DTR) b |= DML_DTR;
49420976Smckusick 	if (bits & DHU_LE) b |= DML_LE;
49520976Smckusick 	return(b);
49620976Smckusick }
49720976Smckusick 
49820976Smckusick 
49920976Smckusick /*
50020976Smckusick  * Set parameters from open or stty into the DHU hardware
501*37606Smarc  * registers.  Impossible values for speed or character
502*37606Smarc  * size are ignored and not copied back into tp.
50320976Smckusick  */
504*37606Smarc dhuparam(tp, want)
505*37606Smarc 	register struct tty *tp;
506*37606Smarc 	register struct termios *want;
50720976Smckusick {
508*37606Smarc 	register int unit = UNIT(tp->t_dev);
509*37606Smarc 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
51020976Smckusick 	register int lpar;
511*37606Smarc 	register long cflag;
512*37606Smarc 	register int incode, outcode;
51320976Smckusick 	int s;
514*37606Smarc 
51520976Smckusick 	/*
51620976Smckusick 	 * Block interrupts so parameters will be set
51720976Smckusick 	 * before the line interrupts.
51820976Smckusick 	 */
519*37606Smarc 	s = spltty();
520*37606Smarc 
521*37606Smarc 	if (want->c_ospeed == 0) {
522*37606Smarc 		tp->t_ospeed = 0;
523*37606Smarc 		tp->t_cflag |= HUPCL;
52420976Smckusick 		(void)dhumctl(unit, DHU_OFF, DMSET);
52520976Smckusick 		splx(s);
52620976Smckusick 		return;
52720976Smckusick 	}
528*37606Smarc 
529*37606Smarc 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
530*37606Smarc 		tp->t_ospeed = want->c_ospeed;
531*37606Smarc 	else
532*37606Smarc 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
533*37606Smarc 
534*37606Smarc 	if (want->c_ispeed == 0) {
535*37606Smarc 		tp->t_ispeed = 0;
536*37606Smarc 		incode = outcode;
537*37606Smarc 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
538*37606Smarc 		tp->t_ispeed = want->c_ispeed;
539*37606Smarc 	else
540*37606Smarc 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
541*37606Smarc 
542*37606Smarc 	lpar = ((char)outcode<<12) | ((char)incode<<8);
543*37606Smarc 
544*37606Smarc 	switch (want->c_cflag&CSIZE) {
545*37606Smarc 	case CS6: case CS7: case CS8:
546*37606Smarc 		tp->t_cflag =  want->c_cflag;
547*37606Smarc 		break;
548*37606Smarc 	default:
549*37606Smarc 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
550*37606Smarc 	}
551*37606Smarc 	cflag = tp->t_cflag;
552*37606Smarc 
553*37606Smarc 	switch(cflag&CSIZE) {
554*37606Smarc 	case CS6:
555*37606Smarc 		lpar |= DHU_LP_BITS6;
556*37606Smarc 		break;
557*37606Smarc 	case CS7:
558*37606Smarc 		lpar |= DHU_LP_BITS7;
559*37606Smarc 		break;
560*37606Smarc 	case CS8:
56120976Smckusick 		lpar |= DHU_LP_BITS8;
562*37606Smarc 		break;
563*37606Smarc 	}
564*37606Smarc 	if (cflag&PARENB) {
565*37606Smarc 		lpar |= DHU_LP_PENABLE;
566*37606Smarc 		if ((cflag&PARODD) == 0)
567*37606Smarc 			lpar |= DHU_LP_EPAR;
568*37606Smarc 	}
569*37606Smarc 	if (cflag&CSTOPB)
570*37606Smarc 		lpar |= DHU_LP_TWOSB;
571*37606Smarc 	if (cflag&CREAD)
572*37606Smarc 		addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
57320976Smckusick 	else
574*37606Smarc 		addr->dhucsr = DHU_SELECT(unit) | DHU_CS_TIE;
575*37606Smarc 
57620976Smckusick 	addr->dhulpr = lpar;
57720976Smckusick 	splx(s);
57820976Smckusick }
57920976Smckusick 
58020976Smckusick /*
58120976Smckusick  * DHU11 transmitter interrupt.
58220976Smckusick  * Restart each line which used to be active but has
58320976Smckusick  * terminated transmission since the last interrupt.
58420976Smckusick  */
58520976Smckusick dhuxint(dhu)
58620976Smckusick 	int dhu;
58720976Smckusick {
58820976Smckusick 	register struct tty *tp;
58920976Smckusick 	register struct dhudevice *addr;
59020976Smckusick 	register struct tty *tp0;
59120976Smckusick 	register struct uba_device *ui;
59220976Smckusick 	register int line, t;
59320976Smckusick 	u_short cntr;
59420976Smckusick 
59535401Stef #ifdef QBA
59627256Skridle 	(void) spl5();
59727256Skridle #endif
59820976Smckusick 	ui = dhuinfo[dhu];
59920976Smckusick 	tp0 = &dhu_tty[dhu<<4];
60020976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
60120976Smckusick 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
60220976Smckusick 		line = DHU_TX_LINE(t);
60320976Smckusick 		tp = tp0 + line;
60420976Smckusick 		tp->t_state &= ~TS_BUSY;
60520976Smckusick 		if (t & DHU_CSH_NXM) {
60620976Smckusick 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
60720976Smckusick 			/* SHOULD RESTART OR SOMETHING... */
60820976Smckusick 		}
60920976Smckusick 		if (tp->t_state&TS_FLUSH)
61020976Smckusick 			tp->t_state &= ~TS_FLUSH;
61120976Smckusick 		else {
61220976Smckusick 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
61320976Smckusick 			/*
61420976Smckusick 			 * Do arithmetic in a short to make up
61520976Smckusick 			 * for lost 16&17 bits.
61620976Smckusick 			 */
61720976Smckusick 			cntr = addr->dhubar1 -
61820976Smckusick 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
61920976Smckusick 			ndflush(&tp->t_outq, (int)cntr);
62020976Smckusick 		}
62120976Smckusick 		if (tp->t_line)
62220976Smckusick 			(*linesw[tp->t_line].l_start)(tp);
62320976Smckusick 		else
62420976Smckusick 			dhustart(tp);
62520976Smckusick 	}
62620976Smckusick }
62720976Smckusick 
62820976Smckusick /*
62920976Smckusick  * Start (restart) transmission on the given DHU11 line.
63020976Smckusick  */
63120976Smckusick dhustart(tp)
63220976Smckusick 	register struct tty *tp;
63320976Smckusick {
63420976Smckusick 	register struct dhudevice *addr;
63520976Smckusick 	register int car, dhu, unit, nch;
63620976Smckusick 	int s;
63720976Smckusick 
63820976Smckusick 	unit = minor(tp->t_dev);
63920976Smckusick 	dhu = unit >> 4;
64020976Smckusick 	unit &= 0xf;
64120976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
64220976Smckusick 
64320976Smckusick 	/*
64420976Smckusick 	 * Must hold interrupts in following code to prevent
64520976Smckusick 	 * state of the tp from changing.
64620976Smckusick 	 */
64720976Smckusick 	s = spl5();
64820976Smckusick 	/*
64920976Smckusick 	 * If it's currently active, or delaying, no need to do anything.
65020976Smckusick 	 */
65120976Smckusick 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
65220976Smckusick 		goto out;
65320976Smckusick 	/*
65420976Smckusick 	 * If there are sleepers, and output has drained below low
65520976Smckusick 	 * water mark, wake up the sleepers..
65620976Smckusick 	 */
657*37606Smarc 	if (tp->t_outq.c_cc <= tp->t_lowat) {
65820976Smckusick 		if (tp->t_state&TS_ASLEEP) {
65920976Smckusick 			tp->t_state &= ~TS_ASLEEP;
66020976Smckusick 			wakeup((caddr_t)&tp->t_outq);
66120976Smckusick 		}
66220976Smckusick 		if (tp->t_wsel) {
66320976Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
66420976Smckusick 			tp->t_wsel = 0;
66520976Smckusick 			tp->t_state &= ~TS_WCOLL;
66620976Smckusick 		}
66720976Smckusick 	}
66820976Smckusick 	/*
66920976Smckusick 	 * Now restart transmission unless the output queue is
67020976Smckusick 	 * empty.
67120976Smckusick 	 */
67220976Smckusick 	if (tp->t_outq.c_cc == 0)
67320976Smckusick 		goto out;
674*37606Smarc 	if (!(tp->t_oflag & OPOST))
67520976Smckusick 		nch = ndqb(&tp->t_outq, 0);
67620976Smckusick 	else {
67720976Smckusick 		nch = ndqb(&tp->t_outq, 0200);
67820976Smckusick 		/*
67920976Smckusick 		 * If first thing on queue is a delay process it.
68020976Smckusick 		 */
68120976Smckusick 		if (nch == 0) {
68220976Smckusick 			nch = getc(&tp->t_outq);
68320976Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
68420976Smckusick 			tp->t_state |= TS_TIMEOUT;
68520976Smckusick 			goto out;
68620976Smckusick 		}
68720976Smckusick 	}
68820976Smckusick 	/*
68920976Smckusick 	 * If characters to transmit, restart transmission.
69020976Smckusick 	 */
69120976Smckusick 	if (nch) {
69220976Smckusick 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
69320976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
69420976Smckusick 		addr->dhulcr &= ~DHU_LC_TXABORT;
69520976Smckusick 		addr->dhubcr = nch;
69620976Smckusick 		addr->dhubar1 = car;
69720976Smckusick 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
69820976Smckusick 					DHU_BA2_DMAGO;
69920976Smckusick 		tp->t_state |= TS_BUSY;
70020976Smckusick 	}
70120976Smckusick out:
70220976Smckusick 	splx(s);
70320976Smckusick }
70420976Smckusick 
70520976Smckusick /*
70620976Smckusick  * Stop output on a line, e.g. for ^S/^Q or output flush.
70720976Smckusick  */
70820976Smckusick /*ARGSUSED*/
70920976Smckusick dhustop(tp, flag)
71020976Smckusick 	register struct tty *tp;
71120976Smckusick {
71220976Smckusick 	register struct dhudevice *addr;
71320976Smckusick 	register int unit, s;
71420976Smckusick 
71520976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
71620976Smckusick 	/*
71720976Smckusick 	 * Block input/output interrupts while messing with state.
71820976Smckusick 	 */
71920976Smckusick 	s = spl5();
72020976Smckusick 	if (tp->t_state & TS_BUSY) {
72120976Smckusick 		/*
72220976Smckusick 		 * Device is transmitting; stop output
72320976Smckusick 		 * by selecting the line and setting the
72420976Smckusick 		 * abort xmit bit.  We will get an xmit interrupt,
72520976Smckusick 		 * where we will figure out where to continue the
72620976Smckusick 		 * next time the transmitter is enabled.  If
72720976Smckusick 		 * TS_FLUSH is set, the outq will be flushed.
72820976Smckusick 		 * In either case, dhustart will clear the TXABORT bit.
72920976Smckusick 		 */
73020976Smckusick 		unit = minor(tp->t_dev);
73120976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
73220976Smckusick 		addr->dhulcr |= DHU_LC_TXABORT;
73320976Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
73420976Smckusick 			tp->t_state |= TS_FLUSH;
73520976Smckusick 	}
73620976Smckusick 	(void) splx(s);
73720976Smckusick }
73820976Smckusick 
73920976Smckusick /*
74020976Smckusick  * DHU11 modem control
74120976Smckusick  */
74220976Smckusick dhumctl(dev, bits, how)
74320976Smckusick 	dev_t dev;
74420976Smckusick 	int bits, how;
74520976Smckusick {
74620976Smckusick 	register struct dhudevice *dhuaddr;
74726291Skarels 	register int unit, mbits;
74820976Smckusick 	int s;
74920976Smckusick 
75020976Smckusick 	unit = UNIT(dev);
75120976Smckusick 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
75220976Smckusick 	unit &= 0xf;
75320976Smckusick 	s = spl5();
75420976Smckusick 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
75520976Smckusick 	/*
75620976Smckusick 	 * combine byte from stat register (read only, bits 16..23)
75720976Smckusick 	 * with lcr register (read write, bits 0..15).
75820976Smckusick 	 */
75920976Smckusick 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
76020976Smckusick 	switch (how) {
76120976Smckusick 	case DMSET:
76220976Smckusick 		mbits = (mbits & 0xff0000) | bits;
76320976Smckusick 		break;
76420976Smckusick 
76520976Smckusick 	case DMBIS:
76620976Smckusick 		mbits |= bits;
76720976Smckusick 		break;
76820976Smckusick 
76920976Smckusick 	case DMBIC:
77020976Smckusick 		mbits &= ~bits;
77120976Smckusick 		break;
77220976Smckusick 
77320976Smckusick 	case DMGET:
77420976Smckusick 		(void) splx(s);
77520976Smckusick 		return(mbits);
77620976Smckusick 	}
77720976Smckusick 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
77820976Smckusick 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
77920976Smckusick 	(void) splx(s);
78020976Smckusick 	return(mbits);
78120976Smckusick }
78220976Smckusick 
78320976Smckusick /*
78420976Smckusick  * Reset state of driver if UBA reset was necessary.
78520976Smckusick  * Reset the line and modem control registers.
78620976Smckusick  * restart transmitters.
78720976Smckusick  */
78820976Smckusick dhureset(uban)
78920976Smckusick 	int uban;
79020976Smckusick {
79120976Smckusick 	register int dhu, unit;
79220976Smckusick 	register struct tty *tp;
79320976Smckusick 	register struct uba_device *ui;
79420976Smckusick 	register struct dhudevice *addr;
79520976Smckusick 	int i;
79620976Smckusick 
79720976Smckusick 	for (dhu = 0; dhu < NDHU; dhu++) {
79820976Smckusick 		ui = dhuinfo[dhu];
79920976Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
80020976Smckusick 			continue;
80120976Smckusick 		printf(" dhu%d", dhu);
80230322Skarels 		if (dhu_uballoc[uban] == dhu) {
80330322Skarels 			int info;
80430322Skarels 
80530322Skarels 			info = uballoc(uban, (caddr_t)cfree,
80630322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
80730322Skarels 			if (info)
80830322Skarels 				cbase[uban] = UBAI_ADDR(info);
80930322Skarels 			else {
81030322Skarels 				printf(" [can't get uba map]");
81130322Skarels 				cbase[uban] = -1;
81230322Skarels 			}
81325434Skarels 		}
81420976Smckusick 		addr = (struct dhudevice *)ui->ui_addr;
81520976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
81620976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
81720976Smckusick 		unit = dhu * 16;
81820976Smckusick 		for (i = 0; i < 16; i++) {
81920976Smckusick 			tp = &dhu_tty[unit];
82020976Smckusick 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
821*37606Smarc 				dhuparam(tp, &tp->t_termios);
82220976Smckusick 				(void)dhumctl(unit, DHU_ON, DMSET);
82320976Smckusick 				tp->t_state &= ~TS_BUSY;
82420976Smckusick 				dhustart(tp);
82520976Smckusick 			}
82620976Smckusick 			unit++;
82720976Smckusick 		}
82820976Smckusick 	}
82920976Smckusick }
83020976Smckusick #endif
831