xref: /csrg-svn/sys/vax/uba/dh.c (revision 2468)
1*2468Swnj /*	dh.c	4.16	81/02/17	*/
213Sbill 
31934Swnj #include "dh.h"
41561Sbill #if NDH11 > 0
52456Swnj #define	DELAY(i)	{ register int j = i; while (--j > 0); }
613Sbill /*
71561Sbill  * DH-11 driver
813Sbill  */
913Sbill #include "../h/param.h"
1013Sbill #include "../h/conf.h"
1113Sbill #include "../h/dir.h"
1213Sbill #include "../h/user.h"
1313Sbill #include "../h/tty.h"
1413Sbill #include "../h/map.h"
1513Sbill #include "../h/pte.h"
162395Swnj #include "../h/buf.h"
1713Sbill #include "../h/uba.h"
18113Sbill #include "../h/bk.h"
191561Sbill #include "../h/clist.h"
201786Sbill #include "../h/mx.h"
21*2468Swnj #include "../h/file.h"
2213Sbill 
23*2468Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
24144Sbill 
25*2468Swnj /*
26*2468Swnj  * Definition of the controller for the auto-configuration program.
27*2468Swnj  */
282395Swnj int	dhcntrlr(), dhslave(), dhrint(), dhxint();
292395Swnj struct	uba_dinfo *dhinfo[NDH11];
302395Swnj u_short	dhstd[] = { 0 };
312395Swnj struct	uba_driver dhdriver =
322456Swnj 	{ dhcntrlr, dhslave, 0, 0, dhstd, "dh", dhinfo };
332395Swnj 
342395Swnj struct	tty dh11[NDH11*16];
35117Sbill int	dhact;
362395Swnj int	ndh11	= NDH11*16;
3713Sbill int	dhstart();
3813Sbill int	ttrstrt();
392421Skre int	dh_ubinfo[MAXNUBA];
402421Skre int	cbase[MAXNUBA];
4113Sbill 
42*2468Swnj /* Bits in dhlpr */
4313Sbill #define	BITS6	01
4413Sbill #define	BITS7	02
4513Sbill #define	BITS8	03
4613Sbill #define	TWOSB	04
4713Sbill #define	PENABLE	020
4813Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */
4913Sbill #define	OPAR	040
5013Sbill #define	HDUPLX	040000
5113Sbill 
522456Swnj /* Bits in dhcsr */
532456Swnj #define	DH_TI	0100000		/* transmit interrupt */
542456Swnj #define	DH_SI	0040000		/* storage interrupt */
552456Swnj #define	DH_TIE	0020000		/* transmit interrupt enable */
562456Swnj #define	DH_SIE	0010000		/* storage interrupt enable */
572456Swnj #define	DH_MC	0004000		/* master clear */
582456Swnj #define	DH_NXM	0002000		/* non-existant memory */
592456Swnj #define	DH_MM	0001000		/* maintenance mode */
602456Swnj #define	DH_CNI	0000400		/* clear non-existant memory interrupt */
612456Swnj #define	DH_RI	0000200		/* receiver interrupt */
622456Swnj #define	DH_RIE	0000100		/* receiver interrupt enable */
6313Sbill 
642456Swnj #define	DH_IE	(DH_TIE|DH_SIE|DH_RIE)
652456Swnj 
662456Swnj /* Bits in dhrcr */
672456Swnj #define	DH_PE	010000		/* parity error */
682456Swnj #define	DH_FE	020000		/* framing error */
692456Swnj #define	DH_DO	040000		/* data overrun */
702456Swnj 
7113Sbill /*
7213Sbill  * DM control bits
7313Sbill  */
742456Swnj #define	DM_ON	03	/* CD lead + line enable */
752456Swnj #define	DM_OFF	01	/* line enable */
762456Swnj #define	DM_DTR	02	/* data terminal ready */
772456Swnj #define	DM_RQS	04	/* request to send */
7813Sbill 
79*2468Swnj /* Software copy of last dhbar */
802395Swnj short	dhsar[NDH11];
8113Sbill 
8213Sbill struct device
8313Sbill {
8413Sbill 	union {
852456Swnj 		short	dhcsr;		/* control-status register */
862456Swnj 		char	dhcsrl;		/* low byte for line select */
8713Sbill 	} un;
882456Swnj 	short	dhrcr;			/* receive character register */
892456Swnj 	short	dhlpr;			/* line parameter register */
902456Swnj 	u_short dhcar;			/* current address register */
912456Swnj 	short	dhbcr;			/* byte count register */
922456Swnj 	u_short	dhbar;			/* buffer active register */
932456Swnj 	short	dhbreak;		/* break control register */
942456Swnj 	short	dhsilo;			/* silo status register */
9513Sbill };
9613Sbill 
972456Swnj /*
982456Swnj  * Routine for configuration to force a dh to interrupt.
992456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1002456Swnj  */
101*2468Swnj /*ARGSUSED*/
1022395Swnj dhcntrlr(ui, reg)
1032395Swnj 	struct uba_dinfo *ui;
1042395Swnj 	caddr_t reg;
1052395Swnj {
106*2468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1072456Swnj 	register struct device *dhaddr = (struct device *)reg;
1082421Skre 	int i;
1092395Swnj 
1102456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1112456Swnj 	DELAY(5);
1122456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1132421Skre 	dhaddr->dhbcr = -1;
1142456Swnj 	dhaddr->dhcar = 0;
1152421Skre 	dhaddr->dhbar = 1;
1162456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1172421Skre 	dhaddr->un.dhcsr = 0;
1182456Swnj 	if (cvec && cvec != 0x200)
1192456Swnj 		cvec -= 4;		/* transmit -> receive */
1202456Swnj 	return (1);
1212395Swnj }
1222395Swnj 
1232456Swnj /*
1242456Swnj  * Routine called to init slave tables.
1252456Swnj  */
1262395Swnj dhslave(ui, reg, slaveno)
1272395Swnj 	struct uba_dinfo *ui;
1282395Swnj 	caddr_t reg;
1292395Swnj {
1302395Swnj 
1312456Swnj 	/* no tables to set up */
1322395Swnj }
1332395Swnj 
13413Sbill /*
135*2468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
136*2468Swnj  * is the first dh on this uba.  Turn on this dh if this is
137*2468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
13813Sbill  */
13913Sbill /*ARGSUSED*/
14013Sbill dhopen(dev, flag)
1412395Swnj 	dev_t dev;
14213Sbill {
14313Sbill 	register struct tty *tp;
1442395Swnj 	register int unit, dh;
14513Sbill 	register struct device *addr;
1462395Swnj 	register struct uba_dinfo *ui;
14713Sbill 	int s;
14813Sbill 
1492395Swnj 	unit = minor(dev);
1502395Swnj 	dh = unit >> 4;
151*2468Swnj 	if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) {
15213Sbill 		u.u_error = ENXIO;
15313Sbill 		return;
15413Sbill 	}
1552395Swnj 	tp = &dh11[unit];
156*2468Swnj 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
157*2468Swnj 		u.u_error = EBUSY;
158*2468Swnj 		return;
159*2468Swnj 	}
1602395Swnj 	addr = (struct device *)ui->ui_addr;
16113Sbill 	tp->t_addr = (caddr_t)addr;
16213Sbill 	tp->t_oproc = dhstart;
16313Sbill 	tp->t_iproc = NULL;
16413Sbill 	tp->t_state |= WOPEN;
165*2468Swnj 	/*
166*2468Swnj 	 * While setting up state for this uba and this dh,
167*2468Swnj 	 * block uba resets which can clear the state.
168*2468Swnj 	 */
169*2468Swnj 	s = spl5();
1702421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
171717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
1722395Swnj 		dh_ubinfo[ui->ui_ubanum] =
1732421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
1742395Swnj 			512+NCLIST*sizeof(struct cblock), 0);
1752456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
17613Sbill 	}
1772456Swnj 	if ((dhact&(1<<dh)) == 0) {
1782456Swnj 		addr->un.dhcsr |= DH_IE;
179*2468Swnj 		DELAY(5);
180*2468Swnj 		dhact |= (1<<dh);
1812456Swnj 		addr->dhsilo = 16;
1822456Swnj 	}
18313Sbill 	splx(s);
184*2468Swnj 	/*
185*2468Swnj 	 * If this is first open, initialze tty state to default.
186*2468Swnj 	 */
18713Sbill 	if ((tp->t_state&ISOPEN) == 0) {
18813Sbill 		ttychars(tp);
189168Sbill 		if (tp->t_ispeed == 0) {
1902456Swnj 			tp->t_ispeed = B300;
1912456Swnj 			tp->t_ospeed = B300;
192168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
193168Sbill 		}
1942395Swnj 		dhparam(unit);
19513Sbill 	}
196*2468Swnj 	/*
197*2468Swnj 	 * Wait for carrier, then process line discipline specific open.
198*2468Swnj 	 */
19913Sbill 	dmopen(dev);
2002395Swnj 	(*linesw[tp->t_line].l_open)(dev, tp);
20113Sbill }
20213Sbill 
20313Sbill /*
204*2468Swnj  * Close a DH11 line, turning off the DM11.
20513Sbill  */
20613Sbill /*ARGSUSED*/
20713Sbill dhclose(dev, flag)
2082395Swnj 	dev_t dev;
2092395Swnj 	int flag;
21013Sbill {
21113Sbill 	register struct tty *tp;
2122395Swnj 	register unit;
21313Sbill 
2142395Swnj 	unit = minor(dev);
2152395Swnj 	tp = &dh11[unit];
21613Sbill 	(*linesw[tp->t_line].l_close)(tp);
2172395Swnj 	((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
21813Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
2192456Swnj 		dmctl(unit, DM_OFF, DMSET);
22013Sbill 	ttyclose(tp);
22113Sbill }
22213Sbill 
22313Sbill dhread(dev)
2242395Swnj 	dev_t dev;
22513Sbill {
2262395Swnj 	register struct tty *tp;
22713Sbill 
2282395Swnj 	tp = &dh11[minor(dev)];
22913Sbill 	(*linesw[tp->t_line].l_read)(tp);
23013Sbill }
23113Sbill 
23213Sbill dhwrite(dev)
2332395Swnj 	dev_t dev;
23413Sbill {
2352395Swnj 	register struct tty *tp;
23613Sbill 
2372395Swnj 	tp = &dh11[minor(dev)];
23813Sbill 	(*linesw[tp->t_line].l_write)(tp);
23913Sbill }
24013Sbill 
24113Sbill /*
24213Sbill  * DH11 receiver interrupt.
24313Sbill  */
2442395Swnj dhrint(dh)
2452395Swnj 	int dh;
24613Sbill {
24713Sbill 	register struct tty *tp;
2482395Swnj 	register c;
24913Sbill 	register struct device *addr;
250117Sbill 	register struct tty *tp0;
2512395Swnj 	register struct uba_dinfo *ui;
252139Sbill 	int s;
25313Sbill 
2542395Swnj 	ui = dhinfo[dh];
2552395Swnj 	addr = (struct device *)ui->ui_addr;
256*2468Swnj 	tp0 = &dh11[dh<<4];
257*2468Swnj 	/*
258*2468Swnj 	 * Loop fetching characters from the silo for this
259*2468Swnj 	 * dh until there are no more in the silo.
260*2468Swnj 	 */
261*2468Swnj 	while ((c = addr->dhrcr) < 0) {
262*2468Swnj 		tp = tp0 + ((c>>8)&0xf);
263*2468Swnj 		if ((tp->t_state&ISOPEN)==0) {
26413Sbill 			wakeup((caddr_t)tp);
26513Sbill 			continue;
26613Sbill 		}
267*2468Swnj 		if (c & DH_PE)
26813Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
26913Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
27013Sbill 				continue;
271*2468Swnj 		if (c & DH_DO)
27213Sbill 			printf("O");
273*2468Swnj 		if (c & DH_FE)
274*2468Swnj 			/*
275*2468Swnj 			 * At framing error (break) generate
276*2468Swnj 			 * a null (in raw mode, for getty), or a
277*2468Swnj 			 * interrupt (in cooked/cbreak mode).
278*2468Swnj 			 */
27913Sbill 			if (tp->t_flags&RAW)
280*2468Swnj 				c = 0;
28113Sbill 			else
282184Sbill 				c = tun.t_intrc;
283139Sbill 		if (tp->t_line == NETLDISC) {
284117Sbill 			c &= 0177;
285168Sbill 			BKINPUT(c, tp);
286117Sbill 		} else
287*2468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
28813Sbill 	}
28913Sbill }
29013Sbill 
29113Sbill /*
292*2468Swnj  * Ioctl for DH11.
29313Sbill  */
29413Sbill /*ARGSUSED*/
29513Sbill dhioctl(dev, cmd, addr, flag)
2962395Swnj 	caddr_t addr;
29713Sbill {
29813Sbill 	register struct tty *tp;
2992395Swnj 	register unit = minor(dev);
30013Sbill 
3012395Swnj 	tp = &dh11[unit];
302113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
303*2468Swnj 	if (cmd == 0)
304113Sbill 		return;
3051895Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
306*2468Swnj 		if (cmd==TIOCSETP || cmd==TIOCSETN)
3072395Swnj 			dhparam(unit);
308168Sbill 	} else switch(cmd) {
309168Sbill 	case TIOCSBRK:
3102395Swnj 		((struct device *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
311168Sbill 		break;
312168Sbill 	case TIOCCBRK:
3132395Swnj 		((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
314168Sbill 		break;
315168Sbill 	case TIOCSDTR:
3162456Swnj 		dmctl(unit, DM_DTR|DM_RQS, DMBIS);
317168Sbill 		break;
318168Sbill 	case TIOCCDTR:
3192456Swnj 		dmctl(unit, DM_DTR|DM_RQS, DMBIC);
320168Sbill 		break;
321168Sbill 	default:
32213Sbill 		u.u_error = ENOTTY;
323168Sbill 	}
32413Sbill }
32513Sbill 
32613Sbill /*
32713Sbill  * Set parameters from open or stty into the DH hardware
32813Sbill  * registers.
32913Sbill  */
3302395Swnj dhparam(unit)
3312395Swnj 	register int unit;
33213Sbill {
33313Sbill 	register struct tty *tp;
33413Sbill 	register struct device *addr;
3352395Swnj 	register int lpar;
336300Sbill 	int s;
33713Sbill 
3382395Swnj 	tp = &dh11[unit];
33913Sbill 	addr = (struct device *)tp->t_addr;
340*2468Swnj 	/*
341*2468Swnj 	 * Block interrupts so parameters will be set
342*2468Swnj 	 * before the line interrupts.
343*2468Swnj 	 */
344300Sbill 	s = spl5();
345*2468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
34613Sbill 	if ((tp->t_ispeed)==0) {
34713Sbill 		tp->t_state |= HUPCLS;
3482456Swnj 		dmctl(unit, DM_OFF, DMSET);
34913Sbill 		return;
35013Sbill 	}
3512395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
352*2468Swnj 	if ((tp->t_ispeed) == B134)
3532395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
3542312Skre 	else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
3552395Swnj 		lpar |= BITS8;
35613Sbill 	else
3572395Swnj 		lpar |= BITS7|PENABLE;
35813Sbill 	if ((tp->t_flags&EVENP) == 0)
3592395Swnj 		lpar |= OPAR;
360*2468Swnj 	if ((tp->t_ospeed) == B110)
3612395Swnj 		lpar |= TWOSB;
3622395Swnj 	addr->dhlpr = lpar;
363300Sbill 	splx(s);
36413Sbill }
36513Sbill 
36613Sbill /*
36713Sbill  * DH11 transmitter interrupt.
36813Sbill  * Restart each line which used to be active but has
36913Sbill  * terminated transmission since the last interrupt.
37013Sbill  */
3712395Swnj dhxint(dh)
3722395Swnj 	int dh;
37313Sbill {
37413Sbill 	register struct tty *tp;
37513Sbill 	register struct device *addr;
37613Sbill 	short ttybit, bar, *sbar;
3772395Swnj 	register struct uba_dinfo *ui;
378*2468Swnj 	register int unit;
379144Sbill 	int s;
380*2468Swnj 	u_short cnt;
38113Sbill 
3822395Swnj 	ui = dhinfo[dh];
3832395Swnj 	addr = (struct device *)ui->ui_addr;
3842456Swnj 	if (addr->un.dhcsr & DH_NXM) {
385*2468Swnj 		DELAY(5);
3862456Swnj 		addr->un.dhcsr |= DH_CNI;
387*2468Swnj 		printf("dh%d NXM\n", dh);
388105Sbill 	}
3892395Swnj 	sbar = &dhsar[dh];
39013Sbill 	bar = *sbar & ~addr->dhbar;
3912395Swnj 	unit = dh * 16; ttybit = 1;
392*2468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
393*2468Swnj 	for (; bar; unit++, ttybit <<= 1) {
394*2468Swnj 		if (bar & ttybit) {
39513Sbill 			*sbar &= ~ttybit;
39613Sbill 			bar &= ~ttybit;
3972395Swnj 			tp = &dh11[unit];
398113Sbill 			tp->t_state &= ~BUSY;
399113Sbill 			if (tp->t_state&FLUSH)
400113Sbill 				tp->t_state &= ~FLUSH;
401113Sbill 			else {
4022456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
403*2468Swnj 				DELAY(5);
404*2468Swnj 				/*
405*2468Swnj 				 * Do arithmetic in a short to make up
406*2468Swnj 				 * for lost 16&17 bits.
407*2468Swnj 				 */
408*2468Swnj 				cnt = addr->dhcar -
409*2468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
410*2468Swnj 				ndflush(&tp->t_outq, cnt);
411113Sbill 			}
412113Sbill 			if (tp->t_line)
41313Sbill 				(*linesw[tp->t_line].l_start)(tp);
414113Sbill 			else
41513Sbill 				dhstart(tp);
41613Sbill 		}
41713Sbill 	}
41813Sbill }
41913Sbill 
42013Sbill /*
42113Sbill  * Start (restart) transmission on the given DH11 line.
42213Sbill  */
42313Sbill dhstart(tp)
4242395Swnj 	register struct tty *tp;
42513Sbill {
42613Sbill 	register struct device *addr;
427*2468Swnj 	register int car, dh, unit, nch;
4282395Swnj 	int s;
42913Sbill 
430*2468Swnj 	unit = minor(tp->t_dev);
431*2468Swnj 	dh = unit >> 4;
432*2468Swnj 	unit &= 0xf;
433*2468Swnj 	addr = (struct device *)tp->t_addr;
434*2468Swnj 
43513Sbill 	/*
436*2468Swnj 	 * Must hold interrupts in following code to prevent
437*2468Swnj 	 * state of the tp from changing.
43813Sbill 	 */
43913Sbill 	s = spl5();
440*2468Swnj 	/*
441*2468Swnj 	 * If it's currently active, or delaying, no need to do anything.
442*2468Swnj 	 */
44313Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
44413Sbill 		goto out;
445*2468Swnj 	/*
446*2468Swnj 	 * If there are sleepers, and output has drained below low
447*2468Swnj 	 * water mark, wake up the sleepers.
448*2468Swnj 	 */
4492395Swnj 	if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
45013Sbill 		tp->t_state &= ~ASLEEP;
45113Sbill 		if (tp->t_chan)
452168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
453168Sbill 		else
45413Sbill 			wakeup((caddr_t)&tp->t_outq);
45513Sbill 	}
456*2468Swnj 	/*
457*2468Swnj 	 * Now restart transmission unless the output queue is
458*2468Swnj 	 * empty.
459*2468Swnj 	 */
46013Sbill 	if (tp->t_outq.c_cc == 0)
46113Sbill 		goto out;
4622395Swnj 	if (tp->t_flags & RAW)
46313Sbill 		nch = ndqb(&tp->t_outq, 0);
4642395Swnj 	else {
46513Sbill 		nch = ndqb(&tp->t_outq, 0200);
466*2468Swnj 		/*
467*2468Swnj 		 * If first thing on queue is a delay process it.
468*2468Swnj 		 */
46913Sbill 		if (nch == 0) {
47013Sbill 			nch = getc(&tp->t_outq);
471*2468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
47213Sbill 			tp->t_state |= TIMEOUT;
47313Sbill 			goto out;
47413Sbill 		}
47513Sbill 	}
476*2468Swnj 	/*
477*2468Swnj 	 * If characters to transmit, restart transmission.
478*2468Swnj 	 */
47913Sbill 	if (nch) {
480*2468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
481*2468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
482*2468Swnj 		DELAY(5);
483*2468Swnj 		unit = 1 << unit;
484*2468Swnj 		dhsar[dh] |= unit;
485*2468Swnj 		addr->dhcar = car;
48613Sbill 		addr->dhbcr = -nch;
487*2468Swnj 		addr->dhbar |= unit;
48813Sbill 		tp->t_state |= BUSY;
48913Sbill 	}
4902395Swnj out:
49113Sbill 	splx(s);
49213Sbill }
49313Sbill 
49413Sbill /*
495*2468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
49613Sbill  */
49713Sbill /*ARGSUSED*/
49813Sbill dhstop(tp, flag)
499*2468Swnj 	register struct tty *tp;
50013Sbill {
501113Sbill 	register struct device *addr;
5022395Swnj 	register int unit, s;
50313Sbill 
504113Sbill 	addr = (struct device *)tp->t_addr;
505*2468Swnj 	/*
506*2468Swnj 	 * Block input/output interrupts while messing with state.
507*2468Swnj 	 */
508*2468Swnj 	s = spl5();
509113Sbill 	if (tp->t_state & BUSY) {
510*2468Swnj 		/*
511*2468Swnj 		 * Device is transmitting; stop output
512*2468Swnj 		 * by selecting the line and setting the byte
513*2468Swnj 		 * count to -1.  We will clean up later
514*2468Swnj 		 * by examining the address where the dh stopped.
515*2468Swnj 		 */
5162395Swnj 		unit = minor(tp->t_dev);
5172456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
518*2468Swnj 		DELAY(5);
51913Sbill 		if ((tp->t_state&TTSTOP)==0)
52013Sbill 			tp->t_state |= FLUSH;
521113Sbill 		addr->dhbcr = -1;
522113Sbill 	}
52313Sbill 	splx(s);
52413Sbill }
52513Sbill 
526168Sbill /*
527280Sbill  * Reset state of driver if UBA reset was necessary.
528280Sbill  * Reset the csrl and lpr registers on open lines, and
529280Sbill  * restart transmitters.
530280Sbill  */
5312395Swnj dhreset(uban)
532*2468Swnj 	int uban;
533280Sbill {
5342395Swnj 	register int dh, unit;
535280Sbill 	register struct tty *tp;
5362395Swnj 	register struct uba_dinfo *ui;
5372421Skre 	int i;
538280Sbill 
5392421Skre 	if (dh_ubinfo[uban] == 0)
5402421Skre 		return;
541280Sbill 	printf(" dh");
5422421Skre 	ubarelse(uban, &dh_ubinfo[uban]);
5432421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
5442421Skre 	    512+NCLIST*sizeof (struct cblock), 0);
5452421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
5462395Swnj 	dh = 0;
5472421Skre 	for (dh = 0; dh < NDH11; dh++) {
5482421Skre 		ui = dhinfo[dh];
5492421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
5502421Skre 			continue;
5512456Swnj 		((struct device *)ui->ui_addr)->un.dhcsr |= DH_IE;
552*2468Swnj 		DELAY(5);
5532456Swnj 		((struct device *)ui->ui_addr)->dhsilo = 16;
5542421Skre 		unit = dh * 16;
5552421Skre 		for (i = 0; i < 16; i++) {
5562421Skre 			tp = &dh11[unit];
5572421Skre 			if (tp->t_state & (ISOPEN|WOPEN)) {
5582421Skre 				dhparam(unit);
5592456Swnj 				dmctl(unit, DM_ON, DMSET);
5602421Skre 				tp->t_state &= ~BUSY;
5612421Skre 				dhstart(tp);
5622421Skre 			}
5632421Skre 			unit++;
564300Sbill 		}
565300Sbill 	}
566300Sbill 	dhtimer();
567280Sbill }
5682395Swnj 
569*2468Swnj /*
570*2468Swnj  * At software clock interrupt time or after a UNIBUS reset
571*2468Swnj  * empty all the dh silos.
572*2468Swnj  */
5732456Swnj dhtimer()
5742456Swnj {
5752456Swnj 	register int dh;
5762456Swnj 
5772456Swnj 	for (dh = 0; dh < NDH11; dh++)
5782456Swnj 		dhrint(dh);
5792456Swnj }
5802456Swnj 
581*2468Swnj /*
582*2468Swnj  * DM-11 driver.
583*2468Swnj  */
584*2468Swnj 
585*2468Swnj /*
586*2468Swnj  * Definition of the controller for the auto-configuration program.
587*2468Swnj  */
588*2468Swnj int	dmcntrlr(), dmslave(), dmintr();
589*2468Swnj struct	uba_dinfo *dminfo[NDH11];
590*2468Swnj u_short	dmstd[] = { 0 };
591*2468Swnj struct	uba_driver dmdriver =
592*2468Swnj 	{ dmcntrlr, dmslave, 0, 0, dmstd, "dm", dminfo };
593*2468Swnj 
594*2468Swnj /* hardware bits */
595*2468Swnj #define	DM_CARRTRANS	040000		/* carrier transition */
596*2468Swnj #define	DM_CLSCAN	004000		/* clear scan */
597*2468Swnj #define	DM_DONE		000200
598*2468Swnj #define	DM_CARRON	000100		/* carrier on */
599*2468Swnj #define	DM_SCENABLE	000040		/* scan enable */
600*2468Swnj #define	DM_SCBUSY	000020		/* scan busy */
601*2468Swnj 
602*2468Swnj struct dmdevice
603*2468Swnj {
604*2468Swnj 	short	dmcsr;
605*2468Swnj 	short	dmlstat;
606*2468Swnj 	short	dmpad1[2];
607*2468Swnj };
608*2468Swnj 
609*2468Swnj dmcntrlr(um, addr)
610*2468Swnj 	struct uba_minfo *um;
611*2468Swnj 	caddr_t addr;
612*2468Swnj {
613*2468Swnj 
614*2468Swnj }
615*2468Swnj 
616*2468Swnj dmslave()
617*2468Swnj {
618*2468Swnj 
619*2468Swnj }
620*2468Swnj 
621*2468Swnj /*
622*2468Swnj  * Turn on the line associated with the dh device dev.
623*2468Swnj  */
624*2468Swnj dmopen(dev)
625*2468Swnj 	dev_t dev;
626*2468Swnj {
627*2468Swnj 	register struct tty *tp;
628*2468Swnj 	register struct dmdevice *addr;
629*2468Swnj 	register struct uba_dinfo *ui;
630*2468Swnj 	register int unit;
631*2468Swnj 	register int dm;
632*2468Swnj 
633*2468Swnj 	unit = minor(dev);
634*2468Swnj 	dm = unit >> 8;
635*2468Swnj 	tp = &dh11[unit];
636*2468Swnj 	if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
637*2468Swnj 		tp->t_state |= CARR_ON;
638*2468Swnj 		return;
639*2468Swnj 	}
640*2468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
641*2468Swnj 	spl5();
642*2468Swnj 	addr->dmcsr &= ~DM_SCENABLE;
643*2468Swnj 	while (addr->dmcsr & DM_SCBUSY)
644*2468Swnj 		;
645*2468Swnj 	addr->dmcsr = unit & 0xf;
646*2468Swnj 	addr->dmlstat = DM_ON;
647*2468Swnj 	if (addr->dmlstat&DM_CARRON)
648*2468Swnj 		tp->t_state |= CARR_ON;
649*2468Swnj 	addr->dmcsr = DH_IE|DM_SCENABLE;
650*2468Swnj 	while ((tp->t_state&CARR_ON)==0)
651*2468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
652*2468Swnj 	spl0();
653*2468Swnj }
654*2468Swnj 
655*2468Swnj /*
656*2468Swnj  * Dump control bits into the DM registers.
657*2468Swnj  */
658*2468Swnj dmctl(dev, bits, how)
659*2468Swnj 	dev_t dev;
660*2468Swnj 	int bits, how;
661*2468Swnj {
662*2468Swnj 	register struct uba_dinfo *ui;
663*2468Swnj 	register struct dmdevice *addr;
664*2468Swnj 	register int unit, s;
665*2468Swnj 	int dm;
666*2468Swnj 
667*2468Swnj 	unit = minor(dev);
668*2468Swnj 	dm = unit >> 4;
669*2468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
670*2468Swnj 		return;
671*2468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
672*2468Swnj 	s = spl5();
673*2468Swnj 	addr->dmcsr &= ~DM_SCENABLE;
674*2468Swnj 	while (addr->dmcsr & DM_SCBUSY)
675*2468Swnj 		;
676*2468Swnj 	addr->dmcsr = unit & 0xf;
677*2468Swnj 	switch(how) {
678*2468Swnj 	case DMSET:
679*2468Swnj 		addr->dmlstat = bits;
680*2468Swnj 		break;
681*2468Swnj 	case DMBIS:
682*2468Swnj 		addr->dmlstat |= bits;
683*2468Swnj 		break;
684*2468Swnj 	case DMBIC:
685*2468Swnj 		addr->dmlstat &= ~bits;
686*2468Swnj 		break;
687*2468Swnj 	}
688*2468Swnj 	addr->dmcsr = DH_IE|DM_SCENABLE;
689*2468Swnj 	splx(s);
690*2468Swnj }
691*2468Swnj 
692*2468Swnj /*
693*2468Swnj  * DM11 interrupt; deal with carrier transitions.
694*2468Swnj  */
695*2468Swnj dmintr(dm)
696*2468Swnj 	register int dm;
697*2468Swnj {
698*2468Swnj 	register struct uba_dinfo *ui;
699*2468Swnj 	register struct tty *tp;
700*2468Swnj 	register struct dmdevice *addr;
701*2468Swnj 
702*2468Swnj 	ui = dminfo[dm];
703*2468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
704*2468Swnj 	if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CARRTRANS) {
705*2468Swnj 		tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
706*2468Swnj 		wakeup((caddr_t)&tp->t_rawq);
707*2468Swnj 		if ((tp->t_state&WOPEN)==0 &&
708*2468Swnj 		    (tp->t_local&LMDMBUF)) {
709*2468Swnj 			if (addr->dmlstat & DM_CARRON) {
710*2468Swnj 				tp->t_state &= ~TTSTOP;
711*2468Swnj 				ttstart(tp);
712*2468Swnj 			} else if ((tp->t_state&TTSTOP) == 0) {
713*2468Swnj 				tp->t_state |= TTSTOP;
714*2468Swnj 				dhstop(tp, 0);
715*2468Swnj 			}
716*2468Swnj 		} else if ((addr->dmlstat&DM_CARRON)==0) {
717*2468Swnj 			if ((tp->t_state&WOPEN)==0 &&
718*2468Swnj 			    (tp->t_local&LNOHANG)==0) {
719*2468Swnj 				gsignal(tp->t_pgrp, SIGHUP);
720*2468Swnj 				gsignal(tp->t_pgrp, SIGCONT);
721*2468Swnj 				addr->dmlstat = 0;
722*2468Swnj 				flushtty(tp, FREAD|FWRITE);
723*2468Swnj 			}
724*2468Swnj 			tp->t_state &= ~CARR_ON;
725*2468Swnj 		} else
726*2468Swnj 			tp->t_state |= CARR_ON;
727*2468Swnj 		addr->dmcsr = DH_IE|DM_SCENABLE;
728*2468Swnj 	}
729*2468Swnj }
730