xref: /csrg-svn/sys/vax/uba/dh.c (revision 2479)
1*2479Swnj /*	dh.c	4.17	81/02/18	*/
213Sbill 
31934Swnj #include "dh.h"
41561Sbill #if NDH11 > 0
52456Swnj #define	DELAY(i)	{ register int j = i; while (--j > 0); }
613Sbill /*
7*2479Swnj  * DH-11/DM-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"
212468Swnj #include "../h/file.h"
2213Sbill 
232468Swnj /*
24*2479Swnj  * Definition of the driver for the auto-configuration program.
25*2479Swnj  * There is one definition for the dh and one for the dm.
262468Swnj  */
272395Swnj int	dhcntrlr(), dhslave(), dhrint(), dhxint();
282395Swnj struct	uba_dinfo *dhinfo[NDH11];
292395Swnj u_short	dhstd[] = { 0 };
302395Swnj struct	uba_driver dhdriver =
31*2479Swnj 	{ dhcntrlr, dhslave, 0, 0, dhstd, "dh11", dhinfo };
322395Swnj 
33*2479Swnj int	dmcntrlr(), dmslave(), dmintr();
34*2479Swnj struct	uba_dinfo *dminfo[NDH11];
35*2479Swnj u_short	dmstd[] = { 0 };
36*2479Swnj struct	uba_driver dmdriver =
37*2479Swnj 	{ dmcntrlr, dmslave, 0, 0, dmstd, "dm11", dminfo };
3813Sbill 
39*2479Swnj struct dhdevice
40*2479Swnj {
41*2479Swnj 	union {
42*2479Swnj 		short	dhcsr;		/* control-status register */
43*2479Swnj 		char	dhcsrl;		/* low byte for line select */
44*2479Swnj 	} un;
45*2479Swnj 	short	dhrcr;			/* receive character register */
46*2479Swnj 	short	dhlpr;			/* line parameter register */
47*2479Swnj 	u_short dhcar;			/* current address register */
48*2479Swnj 	short	dhbcr;			/* byte count register */
49*2479Swnj 	u_short	dhbar;			/* buffer active register */
50*2479Swnj 	short	dhbreak;		/* break control register */
51*2479Swnj 	short	dhsilo;			/* silo status register */
52*2479Swnj };
5313Sbill 
542456Swnj /* Bits in dhcsr */
552456Swnj #define	DH_TI	0100000		/* transmit interrupt */
562456Swnj #define	DH_SI	0040000		/* storage interrupt */
572456Swnj #define	DH_TIE	0020000		/* transmit interrupt enable */
582456Swnj #define	DH_SIE	0010000		/* storage interrupt enable */
592456Swnj #define	DH_MC	0004000		/* master clear */
602456Swnj #define	DH_NXM	0002000		/* non-existant memory */
612456Swnj #define	DH_MM	0001000		/* maintenance mode */
622456Swnj #define	DH_CNI	0000400		/* clear non-existant memory interrupt */
632456Swnj #define	DH_RI	0000200		/* receiver interrupt */
642456Swnj #define	DH_RIE	0000100		/* receiver interrupt enable */
6513Sbill 
66*2479Swnj /* Bits in dhlpr */
67*2479Swnj #define	BITS6	01
68*2479Swnj #define	BITS7	02
69*2479Swnj #define	BITS8	03
70*2479Swnj #define	TWOSB	04
71*2479Swnj #define	PENABLE	020
72*2479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */
73*2479Swnj #define	OPAR	040
74*2479Swnj #define	HDUPLX	040000
75*2479Swnj 
762456Swnj #define	DH_IE	(DH_TIE|DH_SIE|DH_RIE)
772456Swnj 
782456Swnj /* Bits in dhrcr */
79*2479Swnj #define	DH_PE		0010000		/* parity error */
80*2479Swnj #define	DH_FE		0020000		/* framing error */
81*2479Swnj #define	DH_DO		0040000		/* data overrun */
822456Swnj 
83*2479Swnj struct dmdevice
84*2479Swnj {
85*2479Swnj 	short	dmcsr;		/* control status register */
86*2479Swnj 	short	dmlstat;	/* line status register */
87*2479Swnj 	short	dmpad1[2];
88*2479Swnj };
89*2479Swnj 
90*2479Swnj /* bits in dm csr */
91*2479Swnj #define	DM_RF		0100000		/* ring flag */
92*2479Swnj #define	DM_CF		0040000		/* carrier flag */
93*2479Swnj #define	DM_CTS		0020000		/* clear to send */
94*2479Swnj #define	DM_SRF		0010000		/* secondary receive flag */
95*2479Swnj #define	DM_CS		0004000		/* clear scan */
96*2479Swnj #define	DM_CM		0002000		/* clear multiplexor */
97*2479Swnj #define	DM_MM		0001000		/* maintenance mode */
98*2479Swnj #define	DM_STP		0000400		/* step */
99*2479Swnj #define	DM_DONE		0000200		/* scanner is done */
100*2479Swnj #define	DM_IE		0000100		/* interrupt enable */
101*2479Swnj #define	DM_SE		0000040		/* scan enable */
102*2479Swnj #define	DM_BUSY		0000020		/* scan busy */
103*2479Swnj 
104*2479Swnj /* bits in dm lsr */
105*2479Swnj #define	DML_RNG		0000200		/* ring */
106*2479Swnj #define	DML_CAR		0000100		/* carrier detect */
107*2479Swnj #define	DML_CTS		0000040		/* clear to send */
108*2479Swnj #define	DML_SR		0000020		/* secondary receive */
109*2479Swnj #define	DML_ST		0000010		/* secondary transmit */
110*2479Swnj #define	DML_RTS		0000004		/* request to send */
111*2479Swnj #define	DML_DTR		0000002		/* data terminal ready */
112*2479Swnj #define	DML_LE		0000001		/* line enable */
113*2479Swnj 
114*2479Swnj #define	DML_ON		(DML_DTR|DML_LE)
115*2479Swnj #define	DML_OFF		(DML_LE)
116*2479Swnj 
11713Sbill /*
118*2479Swnj  * Local variables for the driver
11913Sbill  */
120*2479Swnj short	dhsar[NDH11];			/* software copy of last bar */
12113Sbill 
122*2479Swnj struct	tty dh11[NDH11*16];
123*2479Swnj int	ndh11	= NDH11*16;
124*2479Swnj int	dhact;				/* mask of active dh's */
125*2479Swnj int	dhstart(), ttrstrt();
12613Sbill 
127*2479Swnj /*
128*2479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
129*2479Swnj  * The UBACVT macro converts a clist space address for unibus uban
130*2479Swnj  * into an i/o space address for the DMA routine.
131*2479Swnj  */
132*2479Swnj int	dh_ubinfo[MAXNUBA];		/* info about allocated unibus map */
133*2479Swnj int	cbase[MAXNUBA];			/* base address in unibus map */
134*2479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
13513Sbill 
1362456Swnj /*
1372456Swnj  * Routine for configuration to force a dh to interrupt.
1382456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1392456Swnj  */
1402468Swnj /*ARGSUSED*/
1412395Swnj dhcntrlr(ui, reg)
1422395Swnj 	struct uba_dinfo *ui;
1432395Swnj 	caddr_t reg;
1442395Swnj {
1452468Swnj 	register int br, cvec;		/* these are ``value-result'' */
146*2479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1472421Skre 	int i;
1482395Swnj 
1492456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1502456Swnj 	DELAY(5);
1512456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1522421Skre 	dhaddr->dhbcr = -1;
1532456Swnj 	dhaddr->dhcar = 0;
1542421Skre 	dhaddr->dhbar = 1;
1552456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1562421Skre 	dhaddr->un.dhcsr = 0;
1572456Swnj 	if (cvec && cvec != 0x200)
1582456Swnj 		cvec -= 4;		/* transmit -> receive */
1592456Swnj 	return (1);
1602395Swnj }
1612395Swnj 
1622456Swnj /*
1632456Swnj  * Routine called to init slave tables.
1642456Swnj  */
1652395Swnj dhslave(ui, reg, slaveno)
1662395Swnj 	struct uba_dinfo *ui;
1672395Swnj 	caddr_t reg;
1682395Swnj {
1692395Swnj 
1702456Swnj 	/* no tables to set up */
1712395Swnj }
1722395Swnj 
17313Sbill /*
174*2479Swnj  * Configuration routine to cause a dm to interrupt.
175*2479Swnj  */
176*2479Swnj dmcntrlr(um, addr)
177*2479Swnj 	struct uba_minfo *um;
178*2479Swnj 	caddr_t addr;
179*2479Swnj {
180*2479Swnj 	register int br, vec;			/* value-result */
181*2479Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)addr;
182*2479Swnj 
183*2479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
184*2479Swnj 	DELAY(20);
185*2479Swnj 	dmaddr->dmcsr = 0;
186*2479Swnj }
187*2479Swnj 
188*2479Swnj dmslave(ui, addr, slave)
189*2479Swnj 	struct uba_dinfo *ui;
190*2479Swnj 	caddr_t addr;
191*2479Swnj 	int slave;
192*2479Swnj {
193*2479Swnj 
194*2479Swnj 	/* no local state to set up */
195*2479Swnj }
196*2479Swnj 
197*2479Swnj /*
1982468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1992468Swnj  * is the first dh on this uba.  Turn on this dh if this is
2002468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
20113Sbill  */
20213Sbill /*ARGSUSED*/
20313Sbill dhopen(dev, flag)
2042395Swnj 	dev_t dev;
20513Sbill {
20613Sbill 	register struct tty *tp;
2072395Swnj 	register int unit, dh;
208*2479Swnj 	register struct dhdevice *addr;
2092395Swnj 	register struct uba_dinfo *ui;
21013Sbill 	int s;
21113Sbill 
2122395Swnj 	unit = minor(dev);
2132395Swnj 	dh = unit >> 4;
2142468Swnj 	if (unit >= NDH11*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) {
21513Sbill 		u.u_error = ENXIO;
21613Sbill 		return;
21713Sbill 	}
2182395Swnj 	tp = &dh11[unit];
2192468Swnj 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
2202468Swnj 		u.u_error = EBUSY;
2212468Swnj 		return;
2222468Swnj 	}
223*2479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
22413Sbill 	tp->t_addr = (caddr_t)addr;
22513Sbill 	tp->t_oproc = dhstart;
22613Sbill 	tp->t_iproc = NULL;
22713Sbill 	tp->t_state |= WOPEN;
2282468Swnj 	/*
2292468Swnj 	 * While setting up state for this uba and this dh,
2302468Swnj 	 * block uba resets which can clear the state.
2312468Swnj 	 */
2322468Swnj 	s = spl5();
2332421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
234717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
2352395Swnj 		dh_ubinfo[ui->ui_ubanum] =
2362421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2372395Swnj 			512+NCLIST*sizeof(struct cblock), 0);
2382456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
23913Sbill 	}
2402456Swnj 	if ((dhact&(1<<dh)) == 0) {
2412456Swnj 		addr->un.dhcsr |= DH_IE;
2422468Swnj 		DELAY(5);
2432468Swnj 		dhact |= (1<<dh);
2442456Swnj 		addr->dhsilo = 16;
2452456Swnj 	}
24613Sbill 	splx(s);
2472468Swnj 	/*
2482468Swnj 	 * If this is first open, initialze tty state to default.
2492468Swnj 	 */
25013Sbill 	if ((tp->t_state&ISOPEN) == 0) {
25113Sbill 		ttychars(tp);
252168Sbill 		if (tp->t_ispeed == 0) {
2532456Swnj 			tp->t_ispeed = B300;
2542456Swnj 			tp->t_ospeed = B300;
255168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
256168Sbill 		}
2572395Swnj 		dhparam(unit);
25813Sbill 	}
2592468Swnj 	/*
2602468Swnj 	 * Wait for carrier, then process line discipline specific open.
2612468Swnj 	 */
26213Sbill 	dmopen(dev);
2632395Swnj 	(*linesw[tp->t_line].l_open)(dev, tp);
26413Sbill }
26513Sbill 
26613Sbill /*
2672468Swnj  * Close a DH11 line, turning off the DM11.
26813Sbill  */
26913Sbill /*ARGSUSED*/
27013Sbill dhclose(dev, flag)
2712395Swnj 	dev_t dev;
2722395Swnj 	int flag;
27313Sbill {
27413Sbill 	register struct tty *tp;
2752395Swnj 	register unit;
27613Sbill 
2772395Swnj 	unit = minor(dev);
2782395Swnj 	tp = &dh11[unit];
27913Sbill 	(*linesw[tp->t_line].l_close)(tp);
280*2479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
28113Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
282*2479Swnj 		dmctl(unit, DML_OFF, DMSET);
28313Sbill 	ttyclose(tp);
28413Sbill }
28513Sbill 
28613Sbill dhread(dev)
2872395Swnj 	dev_t dev;
28813Sbill {
2892395Swnj 	register struct tty *tp;
29013Sbill 
2912395Swnj 	tp = &dh11[minor(dev)];
29213Sbill 	(*linesw[tp->t_line].l_read)(tp);
29313Sbill }
29413Sbill 
29513Sbill dhwrite(dev)
2962395Swnj 	dev_t dev;
29713Sbill {
2982395Swnj 	register struct tty *tp;
29913Sbill 
3002395Swnj 	tp = &dh11[minor(dev)];
30113Sbill 	(*linesw[tp->t_line].l_write)(tp);
30213Sbill }
30313Sbill 
30413Sbill /*
30513Sbill  * DH11 receiver interrupt.
30613Sbill  */
3072395Swnj dhrint(dh)
3082395Swnj 	int dh;
30913Sbill {
31013Sbill 	register struct tty *tp;
3112395Swnj 	register c;
312*2479Swnj 	register struct dhdevice *addr;
313117Sbill 	register struct tty *tp0;
3142395Swnj 	register struct uba_dinfo *ui;
315139Sbill 	int s;
31613Sbill 
3172395Swnj 	ui = dhinfo[dh];
318*2479Swnj 	if (ui == 0 || ui->ui_alive == 0)
319*2479Swnj 		return;
320*2479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3212468Swnj 	tp0 = &dh11[dh<<4];
3222468Swnj 	/*
3232468Swnj 	 * Loop fetching characters from the silo for this
3242468Swnj 	 * dh until there are no more in the silo.
3252468Swnj 	 */
3262468Swnj 	while ((c = addr->dhrcr) < 0) {
3272468Swnj 		tp = tp0 + ((c>>8)&0xf);
3282468Swnj 		if ((tp->t_state&ISOPEN)==0) {
32913Sbill 			wakeup((caddr_t)tp);
33013Sbill 			continue;
33113Sbill 		}
3322468Swnj 		if (c & DH_PE)
33313Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
33413Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
33513Sbill 				continue;
3362468Swnj 		if (c & DH_DO)
33713Sbill 			printf("O");
3382468Swnj 		if (c & DH_FE)
3392468Swnj 			/*
3402468Swnj 			 * At framing error (break) generate
3412468Swnj 			 * a null (in raw mode, for getty), or a
3422468Swnj 			 * interrupt (in cooked/cbreak mode).
3432468Swnj 			 */
34413Sbill 			if (tp->t_flags&RAW)
3452468Swnj 				c = 0;
34613Sbill 			else
347184Sbill 				c = tun.t_intrc;
348139Sbill 		if (tp->t_line == NETLDISC) {
349117Sbill 			c &= 0177;
350168Sbill 			BKINPUT(c, tp);
351117Sbill 		} else
3522468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
35313Sbill 	}
35413Sbill }
35513Sbill 
35613Sbill /*
3572468Swnj  * Ioctl for DH11.
35813Sbill  */
35913Sbill /*ARGSUSED*/
36013Sbill dhioctl(dev, cmd, addr, flag)
3612395Swnj 	caddr_t addr;
36213Sbill {
36313Sbill 	register struct tty *tp;
3642395Swnj 	register unit = minor(dev);
36513Sbill 
3662395Swnj 	tp = &dh11[unit];
367113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
3682468Swnj 	if (cmd == 0)
369113Sbill 		return;
3701895Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
3712468Swnj 		if (cmd==TIOCSETP || cmd==TIOCSETN)
3722395Swnj 			dhparam(unit);
373168Sbill 	} else switch(cmd) {
374168Sbill 	case TIOCSBRK:
375*2479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
376168Sbill 		break;
377168Sbill 	case TIOCCBRK:
378*2479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
379168Sbill 		break;
380168Sbill 	case TIOCSDTR:
381*2479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
382168Sbill 		break;
383168Sbill 	case TIOCCDTR:
384*2479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
385168Sbill 		break;
386168Sbill 	default:
38713Sbill 		u.u_error = ENOTTY;
388168Sbill 	}
38913Sbill }
39013Sbill 
39113Sbill /*
39213Sbill  * Set parameters from open or stty into the DH hardware
39313Sbill  * registers.
39413Sbill  */
3952395Swnj dhparam(unit)
3962395Swnj 	register int unit;
39713Sbill {
39813Sbill 	register struct tty *tp;
399*2479Swnj 	register struct dhdevice *addr;
4002395Swnj 	register int lpar;
401300Sbill 	int s;
40213Sbill 
4032395Swnj 	tp = &dh11[unit];
404*2479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4052468Swnj 	/*
4062468Swnj 	 * Block interrupts so parameters will be set
4072468Swnj 	 * before the line interrupts.
4082468Swnj 	 */
409300Sbill 	s = spl5();
4102468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
41113Sbill 	if ((tp->t_ispeed)==0) {
41213Sbill 		tp->t_state |= HUPCLS;
413*2479Swnj 		dmctl(unit, DML_OFF, DMSET);
41413Sbill 		return;
41513Sbill 	}
4162395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4172468Swnj 	if ((tp->t_ispeed) == B134)
4182395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4192312Skre 	else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
4202395Swnj 		lpar |= BITS8;
42113Sbill 	else
4222395Swnj 		lpar |= BITS7|PENABLE;
42313Sbill 	if ((tp->t_flags&EVENP) == 0)
4242395Swnj 		lpar |= OPAR;
4252468Swnj 	if ((tp->t_ospeed) == B110)
4262395Swnj 		lpar |= TWOSB;
4272395Swnj 	addr->dhlpr = lpar;
428300Sbill 	splx(s);
42913Sbill }
43013Sbill 
43113Sbill /*
43213Sbill  * DH11 transmitter interrupt.
43313Sbill  * Restart each line which used to be active but has
43413Sbill  * terminated transmission since the last interrupt.
43513Sbill  */
4362395Swnj dhxint(dh)
4372395Swnj 	int dh;
43813Sbill {
43913Sbill 	register struct tty *tp;
440*2479Swnj 	register struct dhdevice *addr;
44113Sbill 	short ttybit, bar, *sbar;
4422395Swnj 	register struct uba_dinfo *ui;
4432468Swnj 	register int unit;
444144Sbill 	int s;
4452468Swnj 	u_short cnt;
44613Sbill 
4472395Swnj 	ui = dhinfo[dh];
448*2479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4492456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4502468Swnj 		DELAY(5);
4512456Swnj 		addr->un.dhcsr |= DH_CNI;
4522468Swnj 		printf("dh%d NXM\n", dh);
453105Sbill 	}
4542395Swnj 	sbar = &dhsar[dh];
45513Sbill 	bar = *sbar & ~addr->dhbar;
4562395Swnj 	unit = dh * 16; ttybit = 1;
4572468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4582468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4592468Swnj 		if (bar & ttybit) {
46013Sbill 			*sbar &= ~ttybit;
46113Sbill 			bar &= ~ttybit;
4622395Swnj 			tp = &dh11[unit];
463113Sbill 			tp->t_state &= ~BUSY;
464113Sbill 			if (tp->t_state&FLUSH)
465113Sbill 				tp->t_state &= ~FLUSH;
466113Sbill 			else {
4672456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4682468Swnj 				DELAY(5);
4692468Swnj 				/*
4702468Swnj 				 * Do arithmetic in a short to make up
4712468Swnj 				 * for lost 16&17 bits.
4722468Swnj 				 */
4732468Swnj 				cnt = addr->dhcar -
4742468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4752468Swnj 				ndflush(&tp->t_outq, cnt);
476113Sbill 			}
477113Sbill 			if (tp->t_line)
47813Sbill 				(*linesw[tp->t_line].l_start)(tp);
479113Sbill 			else
48013Sbill 				dhstart(tp);
48113Sbill 		}
48213Sbill 	}
48313Sbill }
48413Sbill 
48513Sbill /*
48613Sbill  * Start (restart) transmission on the given DH11 line.
48713Sbill  */
48813Sbill dhstart(tp)
4892395Swnj 	register struct tty *tp;
49013Sbill {
491*2479Swnj 	register struct dhdevice *addr;
4922468Swnj 	register int car, dh, unit, nch;
4932395Swnj 	int s;
49413Sbill 
4952468Swnj 	unit = minor(tp->t_dev);
4962468Swnj 	dh = unit >> 4;
4972468Swnj 	unit &= 0xf;
498*2479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4992468Swnj 
50013Sbill 	/*
5012468Swnj 	 * Must hold interrupts in following code to prevent
5022468Swnj 	 * state of the tp from changing.
50313Sbill 	 */
50413Sbill 	s = spl5();
5052468Swnj 	/*
5062468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5072468Swnj 	 */
50813Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
50913Sbill 		goto out;
5102468Swnj 	/*
5112468Swnj 	 * If there are sleepers, and output has drained below low
5122468Swnj 	 * water mark, wake up the sleepers.
5132468Swnj 	 */
5142395Swnj 	if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
51513Sbill 		tp->t_state &= ~ASLEEP;
51613Sbill 		if (tp->t_chan)
517168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
518168Sbill 		else
51913Sbill 			wakeup((caddr_t)&tp->t_outq);
52013Sbill 	}
5212468Swnj 	/*
5222468Swnj 	 * Now restart transmission unless the output queue is
5232468Swnj 	 * empty.
5242468Swnj 	 */
52513Sbill 	if (tp->t_outq.c_cc == 0)
52613Sbill 		goto out;
5272395Swnj 	if (tp->t_flags & RAW)
52813Sbill 		nch = ndqb(&tp->t_outq, 0);
5292395Swnj 	else {
53013Sbill 		nch = ndqb(&tp->t_outq, 0200);
5312468Swnj 		/*
5322468Swnj 		 * If first thing on queue is a delay process it.
5332468Swnj 		 */
53413Sbill 		if (nch == 0) {
53513Sbill 			nch = getc(&tp->t_outq);
5362468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
53713Sbill 			tp->t_state |= TIMEOUT;
53813Sbill 			goto out;
53913Sbill 		}
54013Sbill 	}
5412468Swnj 	/*
5422468Swnj 	 * If characters to transmit, restart transmission.
5432468Swnj 	 */
54413Sbill 	if (nch) {
5452468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5462468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5472468Swnj 		DELAY(5);
5482468Swnj 		unit = 1 << unit;
5492468Swnj 		dhsar[dh] |= unit;
5502468Swnj 		addr->dhcar = car;
55113Sbill 		addr->dhbcr = -nch;
5522468Swnj 		addr->dhbar |= unit;
55313Sbill 		tp->t_state |= BUSY;
55413Sbill 	}
5552395Swnj out:
55613Sbill 	splx(s);
55713Sbill }
55813Sbill 
55913Sbill /*
5602468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
56113Sbill  */
56213Sbill /*ARGSUSED*/
56313Sbill dhstop(tp, flag)
5642468Swnj 	register struct tty *tp;
56513Sbill {
566*2479Swnj 	register struct dhdevice *addr;
5672395Swnj 	register int unit, s;
56813Sbill 
569*2479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5702468Swnj 	/*
5712468Swnj 	 * Block input/output interrupts while messing with state.
5722468Swnj 	 */
5732468Swnj 	s = spl5();
574113Sbill 	if (tp->t_state & BUSY) {
5752468Swnj 		/*
5762468Swnj 		 * Device is transmitting; stop output
5772468Swnj 		 * by selecting the line and setting the byte
5782468Swnj 		 * count to -1.  We will clean up later
5792468Swnj 		 * by examining the address where the dh stopped.
5802468Swnj 		 */
5812395Swnj 		unit = minor(tp->t_dev);
5822456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
5832468Swnj 		DELAY(5);
58413Sbill 		if ((tp->t_state&TTSTOP)==0)
58513Sbill 			tp->t_state |= FLUSH;
586113Sbill 		addr->dhbcr = -1;
587113Sbill 	}
58813Sbill 	splx(s);
58913Sbill }
59013Sbill 
591168Sbill /*
592280Sbill  * Reset state of driver if UBA reset was necessary.
593280Sbill  * Reset the csrl and lpr registers on open lines, and
594280Sbill  * restart transmitters.
595280Sbill  */
5962395Swnj dhreset(uban)
5972468Swnj 	int uban;
598280Sbill {
5992395Swnj 	register int dh, unit;
600280Sbill 	register struct tty *tp;
6012395Swnj 	register struct uba_dinfo *ui;
6022421Skre 	int i;
603280Sbill 
6042421Skre 	if (dh_ubinfo[uban] == 0)
6052421Skre 		return;
606280Sbill 	printf(" dh");
6072421Skre 	ubarelse(uban, &dh_ubinfo[uban]);
6082421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6092421Skre 	    512+NCLIST*sizeof (struct cblock), 0);
6102421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
6112395Swnj 	dh = 0;
6122421Skre 	for (dh = 0; dh < NDH11; dh++) {
6132421Skre 		ui = dhinfo[dh];
6142421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6152421Skre 			continue;
616*2479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
6172468Swnj 		DELAY(5);
618*2479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
6192421Skre 		unit = dh * 16;
6202421Skre 		for (i = 0; i < 16; i++) {
6212421Skre 			tp = &dh11[unit];
6222421Skre 			if (tp->t_state & (ISOPEN|WOPEN)) {
6232421Skre 				dhparam(unit);
624*2479Swnj 				dmctl(unit, DML_ON, DMSET);
6252421Skre 				tp->t_state &= ~BUSY;
6262421Skre 				dhstart(tp);
6272421Skre 			}
6282421Skre 			unit++;
629300Sbill 		}
630300Sbill 	}
631300Sbill 	dhtimer();
632280Sbill }
6332395Swnj 
6342468Swnj /*
6352468Swnj  * At software clock interrupt time or after a UNIBUS reset
6362468Swnj  * empty all the dh silos.
6372468Swnj  */
6382456Swnj dhtimer()
6392456Swnj {
6402456Swnj 	register int dh;
6412456Swnj 
6422456Swnj 	for (dh = 0; dh < NDH11; dh++)
6432456Swnj 		dhrint(dh);
6442456Swnj }
6452456Swnj 
6462468Swnj /*
647*2479Swnj  * Turn on the line associated with dh dev.
6482468Swnj  */
6492468Swnj dmopen(dev)
6502468Swnj 	dev_t dev;
6512468Swnj {
6522468Swnj 	register struct tty *tp;
6532468Swnj 	register struct dmdevice *addr;
6542468Swnj 	register struct uba_dinfo *ui;
6552468Swnj 	register int unit;
6562468Swnj 	register int dm;
6572468Swnj 
6582468Swnj 	unit = minor(dev);
659*2479Swnj 	dm = unit >> 4;
6602468Swnj 	tp = &dh11[unit];
6612468Swnj 	if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
6622468Swnj 		tp->t_state |= CARR_ON;
6632468Swnj 		return;
6642468Swnj 	}
6652468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6662468Swnj 	spl5();
667*2479Swnj 	addr->dmcsr &= ~DM_SE;
668*2479Swnj 	while (addr->dmcsr & DM_BUSY)
6692468Swnj 		;
6702468Swnj 	addr->dmcsr = unit & 0xf;
671*2479Swnj 	addr->dmlstat = DML_ON;
672*2479Swnj 	if (addr->dmlstat&DML_CAR)
6732468Swnj 		tp->t_state |= CARR_ON;
674*2479Swnj 	addr->dmcsr = DH_IE|DM_SE;
6752468Swnj 	while ((tp->t_state&CARR_ON)==0)
6762468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
6772468Swnj 	spl0();
6782468Swnj }
6792468Swnj 
6802468Swnj /*
6812468Swnj  * Dump control bits into the DM registers.
6822468Swnj  */
6832468Swnj dmctl(dev, bits, how)
6842468Swnj 	dev_t dev;
6852468Swnj 	int bits, how;
6862468Swnj {
6872468Swnj 	register struct uba_dinfo *ui;
6882468Swnj 	register struct dmdevice *addr;
6892468Swnj 	register int unit, s;
6902468Swnj 	int dm;
6912468Swnj 
6922468Swnj 	unit = minor(dev);
6932468Swnj 	dm = unit >> 4;
6942468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
6952468Swnj 		return;
6962468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6972468Swnj 	s = spl5();
698*2479Swnj 	addr->dmcsr &= ~DM_SE;
699*2479Swnj 	while (addr->dmcsr & DM_BUSY)
7002468Swnj 		;
7012468Swnj 	addr->dmcsr = unit & 0xf;
7022468Swnj 	switch(how) {
7032468Swnj 	case DMSET:
7042468Swnj 		addr->dmlstat = bits;
7052468Swnj 		break;
7062468Swnj 	case DMBIS:
7072468Swnj 		addr->dmlstat |= bits;
7082468Swnj 		break;
7092468Swnj 	case DMBIC:
7102468Swnj 		addr->dmlstat &= ~bits;
7112468Swnj 		break;
7122468Swnj 	}
713*2479Swnj 	addr->dmcsr = DH_IE|DM_SE;
7142468Swnj 	splx(s);
7152468Swnj }
7162468Swnj 
7172468Swnj /*
7182468Swnj  * DM11 interrupt; deal with carrier transitions.
7192468Swnj  */
7202468Swnj dmintr(dm)
7212468Swnj 	register int dm;
7222468Swnj {
7232468Swnj 	register struct uba_dinfo *ui;
7242468Swnj 	register struct tty *tp;
7252468Swnj 	register struct dmdevice *addr;
7262468Swnj 
7272468Swnj 	ui = dminfo[dm];
728*2479Swnj 	if (ui == 0)
729*2479Swnj 		return;
7302468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
731*2479Swnj 	if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CF) {
7322468Swnj 		tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
7332468Swnj 		wakeup((caddr_t)&tp->t_rawq);
7342468Swnj 		if ((tp->t_state&WOPEN)==0 &&
7352468Swnj 		    (tp->t_local&LMDMBUF)) {
736*2479Swnj 			if (addr->dmlstat & DML_CAR) {
7372468Swnj 				tp->t_state &= ~TTSTOP;
7382468Swnj 				ttstart(tp);
7392468Swnj 			} else if ((tp->t_state&TTSTOP) == 0) {
7402468Swnj 				tp->t_state |= TTSTOP;
7412468Swnj 				dhstop(tp, 0);
7422468Swnj 			}
743*2479Swnj 		} else if ((addr->dmlstat&DML_CAR)==0) {
7442468Swnj 			if ((tp->t_state&WOPEN)==0 &&
7452468Swnj 			    (tp->t_local&LNOHANG)==0) {
7462468Swnj 				gsignal(tp->t_pgrp, SIGHUP);
7472468Swnj 				gsignal(tp->t_pgrp, SIGCONT);
7482468Swnj 				addr->dmlstat = 0;
7492468Swnj 				flushtty(tp, FREAD|FWRITE);
7502468Swnj 			}
7512468Swnj 			tp->t_state &= ~CARR_ON;
7522468Swnj 		} else
7532468Swnj 			tp->t_state |= CARR_ON;
754*2479Swnj 		addr->dmcsr = DH_IE|DM_SE;
7552468Swnj 	}
7562468Swnj }
757