xref: /csrg-svn/sys/vax/uba/dh.c (revision 2974)
1*2974Swnj /*	dh.c	4.28	81/03/07	*/
213Sbill 
31934Swnj #include "dh.h"
42643Swnj #if NDH > 0
52456Swnj #define	DELAY(i)	{ register int j = i; while (--j > 0); }
613Sbill /*
72479Swnj  * DH-11/DM-11 driver
813Sbill  */
92730Swnj #include "bk.h"
1013Sbill #include "../h/param.h"
1113Sbill #include "../h/conf.h"
1213Sbill #include "../h/dir.h"
1313Sbill #include "../h/user.h"
1413Sbill #include "../h/tty.h"
1513Sbill #include "../h/map.h"
1613Sbill #include "../h/pte.h"
172395Swnj #include "../h/buf.h"
182566Swnj #include "../h/vm.h"
19*2974Swnj #include "../h/ubareg.h"
20*2974Swnj #include "../h/ubavar.h"
21113Sbill #include "../h/bk.h"
221561Sbill #include "../h/clist.h"
231786Sbill #include "../h/mx.h"
242468Swnj #include "../h/file.h"
2513Sbill 
262468Swnj /*
272479Swnj  * Definition of the driver for the auto-configuration program.
282479Swnj  * There is one definition for the dh and one for the dm.
292468Swnj  */
302605Swnj int	dhprobe(), dhattach(), dhrint(), dhxint();
31*2974Swnj struct	uba_device *dhinfo[NDH];
322395Swnj u_short	dhstd[] = { 0 };
332395Swnj struct	uba_driver dhdriver =
342605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
352395Swnj 
362605Swnj int	dmprobe(), dmattach(), dmintr();
37*2974Swnj struct	uba_device *dminfo[NDH];
382479Swnj u_short	dmstd[] = { 0 };
392479Swnj struct	uba_driver dmdriver =
402605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
4113Sbill 
422479Swnj struct dhdevice
432479Swnj {
442479Swnj 	union {
452479Swnj 		short	dhcsr;		/* control-status register */
462479Swnj 		char	dhcsrl;		/* low byte for line select */
472479Swnj 	} un;
482479Swnj 	short	dhrcr;			/* receive character register */
492479Swnj 	short	dhlpr;			/* line parameter register */
502479Swnj 	u_short dhcar;			/* current address register */
512479Swnj 	short	dhbcr;			/* byte count register */
522479Swnj 	u_short	dhbar;			/* buffer active register */
532479Swnj 	short	dhbreak;		/* break control register */
542479Swnj 	short	dhsilo;			/* silo status register */
552479Swnj };
5613Sbill 
572456Swnj /* Bits in dhcsr */
582456Swnj #define	DH_TI	0100000		/* transmit interrupt */
592456Swnj #define	DH_SI	0040000		/* storage interrupt */
602456Swnj #define	DH_TIE	0020000		/* transmit interrupt enable */
612456Swnj #define	DH_SIE	0010000		/* storage interrupt enable */
622456Swnj #define	DH_MC	0004000		/* master clear */
632456Swnj #define	DH_NXM	0002000		/* non-existant memory */
642456Swnj #define	DH_MM	0001000		/* maintenance mode */
652456Swnj #define	DH_CNI	0000400		/* clear non-existant memory interrupt */
662456Swnj #define	DH_RI	0000200		/* receiver interrupt */
672456Swnj #define	DH_RIE	0000100		/* receiver interrupt enable */
6813Sbill 
692479Swnj /* Bits in dhlpr */
702479Swnj #define	BITS6	01
712479Swnj #define	BITS7	02
722479Swnj #define	BITS8	03
732479Swnj #define	TWOSB	04
742479Swnj #define	PENABLE	020
752479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */
762479Swnj #define	OPAR	040
772479Swnj #define	HDUPLX	040000
782479Swnj 
792456Swnj #define	DH_IE	(DH_TIE|DH_SIE|DH_RIE)
802456Swnj 
812456Swnj /* Bits in dhrcr */
822479Swnj #define	DH_PE		0010000		/* parity error */
832479Swnj #define	DH_FE		0020000		/* framing error */
842479Swnj #define	DH_DO		0040000		/* data overrun */
852456Swnj 
862479Swnj struct dmdevice
872479Swnj {
882479Swnj 	short	dmcsr;		/* control status register */
892479Swnj 	short	dmlstat;	/* line status register */
902479Swnj 	short	dmpad1[2];
912479Swnj };
922479Swnj 
932479Swnj /* bits in dm csr */
942479Swnj #define	DM_RF		0100000		/* ring flag */
952479Swnj #define	DM_CF		0040000		/* carrier flag */
962479Swnj #define	DM_CTS		0020000		/* clear to send */
972479Swnj #define	DM_SRF		0010000		/* secondary receive flag */
982479Swnj #define	DM_CS		0004000		/* clear scan */
992479Swnj #define	DM_CM		0002000		/* clear multiplexor */
1002479Swnj #define	DM_MM		0001000		/* maintenance mode */
1012479Swnj #define	DM_STP		0000400		/* step */
1022479Swnj #define	DM_DONE		0000200		/* scanner is done */
1032479Swnj #define	DM_IE		0000100		/* interrupt enable */
1042479Swnj #define	DM_SE		0000040		/* scan enable */
1052479Swnj #define	DM_BUSY		0000020		/* scan busy */
1062479Swnj 
1072479Swnj /* bits in dm lsr */
1082479Swnj #define	DML_RNG		0000200		/* ring */
1092479Swnj #define	DML_CAR		0000100		/* carrier detect */
1102479Swnj #define	DML_CTS		0000040		/* clear to send */
1112479Swnj #define	DML_SR		0000020		/* secondary receive */
1122479Swnj #define	DML_ST		0000010		/* secondary transmit */
1132479Swnj #define	DML_RTS		0000004		/* request to send */
1142479Swnj #define	DML_DTR		0000002		/* data terminal ready */
1152479Swnj #define	DML_LE		0000001		/* line enable */
1162479Swnj 
1172479Swnj #define	DML_ON		(DML_DTR|DML_LE)
1182479Swnj #define	DML_OFF		(DML_LE)
1192479Swnj 
12013Sbill /*
1212479Swnj  * Local variables for the driver
12213Sbill  */
1232643Swnj short	dhsar[NDH];			/* software copy of last bar */
1242643Swnj short	dhsoftCAR[NDH];
12513Sbill 
1262643Swnj struct	tty dh11[NDH*16];
1272643Swnj int	ndh11	= NDH*16;
1282479Swnj int	dhact;				/* mask of active dh's */
1292479Swnj int	dhstart(), ttrstrt();
13013Sbill 
1312479Swnj /*
1322479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
1332479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1342479Swnj  * into an i/o space address for the DMA routine.
1352479Swnj  */
1362479Swnj int	dh_ubinfo[MAXNUBA];		/* info about allocated unibus map */
1372479Swnj int	cbase[MAXNUBA];			/* base address in unibus map */
1382479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
13913Sbill 
1402456Swnj /*
1412456Swnj  * Routine for configuration to force a dh to interrupt.
1422456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1432456Swnj  */
1442468Swnj /*ARGSUSED*/
1452605Swnj dhprobe(reg)
1462395Swnj 	caddr_t reg;
1472395Swnj {
1482468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1492479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1502395Swnj 
1512605Swnj #ifdef lint
1522605Swnj 	br = 0; cvec = br; br = cvec;
1532605Swnj #endif
1542696Swnj #ifndef notdef
1552566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1562566Swnj 	DELAY(5);
1572566Swnj 	dhaddr->un.dhcsr = 0;
1582566Swnj #else
1592456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1602456Swnj 	DELAY(5);
1612456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1622421Skre 	dhaddr->dhbcr = -1;
1632456Swnj 	dhaddr->dhcar = 0;
1642421Skre 	dhaddr->dhbar = 1;
1652456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1662421Skre 	dhaddr->un.dhcsr = 0;
1672456Swnj 	if (cvec && cvec != 0x200)
1682456Swnj 		cvec -= 4;		/* transmit -> receive */
1692482Swnj #endif
1702456Swnj 	return (1);
1712395Swnj }
1722395Swnj 
1732456Swnj /*
1742605Swnj  * Routine called to attach a dh.
1752456Swnj  */
1762605Swnj dhattach(ui)
177*2974Swnj 	struct uba_device *ui;
1782395Swnj {
1792395Swnj 
1802566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1812395Swnj }
1822395Swnj 
18313Sbill /*
1842479Swnj  * Configuration routine to cause a dm to interrupt.
1852479Swnj  */
1862605Swnj dmprobe(reg)
1872605Swnj 	caddr_t reg;
1882479Swnj {
1892479Swnj 	register int br, vec;			/* value-result */
1902605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1912479Swnj 
1922605Swnj #ifdef lint
1932605Swnj 	br = 0; cvec = br; br = cvec;
1942605Swnj #endif
1952479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1962479Swnj 	DELAY(20);
1972479Swnj 	dmaddr->dmcsr = 0;
1982605Swnj 	return (1);
1992479Swnj }
2002479Swnj 
2012605Swnj /*ARGSUSED*/
2022605Swnj dmattach(ui)
203*2974Swnj 	struct uba_device *ui;
2042479Swnj {
2052479Swnj 
2062479Swnj 	/* no local state to set up */
2072479Swnj }
2082479Swnj 
2092479Swnj /*
2102468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
2112468Swnj  * is the first dh on this uba.  Turn on this dh if this is
2122468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
21313Sbill  */
21413Sbill /*ARGSUSED*/
21513Sbill dhopen(dev, flag)
2162395Swnj 	dev_t dev;
21713Sbill {
21813Sbill 	register struct tty *tp;
2192395Swnj 	register int unit, dh;
2202479Swnj 	register struct dhdevice *addr;
221*2974Swnj 	register struct uba_device *ui;
22213Sbill 	int s;
22313Sbill 
2242395Swnj 	unit = minor(dev);
2252395Swnj 	dh = unit >> 4;
2262643Swnj 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) {
22713Sbill 		u.u_error = ENXIO;
22813Sbill 		return;
22913Sbill 	}
2302395Swnj 	tp = &dh11[unit];
2312468Swnj 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
2322468Swnj 		u.u_error = EBUSY;
2332468Swnj 		return;
2342468Swnj 	}
2352479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
23613Sbill 	tp->t_addr = (caddr_t)addr;
23713Sbill 	tp->t_oproc = dhstart;
23813Sbill 	tp->t_iproc = NULL;
23913Sbill 	tp->t_state |= WOPEN;
2402468Swnj 	/*
2412468Swnj 	 * While setting up state for this uba and this dh,
2422468Swnj 	 * block uba resets which can clear the state.
2432468Swnj 	 */
2442468Swnj 	s = spl5();
2452421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
246717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
2472395Swnj 		dh_ubinfo[ui->ui_ubanum] =
2482421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2492770Swnj 			512+nclist*sizeof(struct cblock), 0);
2502456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
25113Sbill 	}
2522456Swnj 	if ((dhact&(1<<dh)) == 0) {
2532456Swnj 		addr->un.dhcsr |= DH_IE;
2542468Swnj 		dhact |= (1<<dh);
2552456Swnj 		addr->dhsilo = 16;
2562456Swnj 	}
25713Sbill 	splx(s);
2582468Swnj 	/*
2592468Swnj 	 * If this is first open, initialze tty state to default.
2602468Swnj 	 */
26113Sbill 	if ((tp->t_state&ISOPEN) == 0) {
26213Sbill 		ttychars(tp);
263168Sbill 		if (tp->t_ispeed == 0) {
2642456Swnj 			tp->t_ispeed = B300;
2652456Swnj 			tp->t_ospeed = B300;
266168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
267168Sbill 		}
2682395Swnj 		dhparam(unit);
26913Sbill 	}
2702468Swnj 	/*
2712468Swnj 	 * Wait for carrier, then process line discipline specific open.
2722468Swnj 	 */
27313Sbill 	dmopen(dev);
2742395Swnj 	(*linesw[tp->t_line].l_open)(dev, tp);
27513Sbill }
27613Sbill 
27713Sbill /*
2782468Swnj  * Close a DH11 line, turning off the DM11.
27913Sbill  */
28013Sbill /*ARGSUSED*/
28113Sbill dhclose(dev, flag)
2822395Swnj 	dev_t dev;
2832395Swnj 	int flag;
28413Sbill {
28513Sbill 	register struct tty *tp;
2862395Swnj 	register unit;
28713Sbill 
2882395Swnj 	unit = minor(dev);
2892395Swnj 	tp = &dh11[unit];
29013Sbill 	(*linesw[tp->t_line].l_close)(tp);
2912479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
29213Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
2932479Swnj 		dmctl(unit, DML_OFF, DMSET);
29413Sbill 	ttyclose(tp);
29513Sbill }
29613Sbill 
29713Sbill dhread(dev)
2982395Swnj 	dev_t dev;
29913Sbill {
3002395Swnj 	register struct tty *tp;
30113Sbill 
3022395Swnj 	tp = &dh11[minor(dev)];
30313Sbill 	(*linesw[tp->t_line].l_read)(tp);
30413Sbill }
30513Sbill 
30613Sbill dhwrite(dev)
3072395Swnj 	dev_t dev;
30813Sbill {
3092395Swnj 	register struct tty *tp;
31013Sbill 
3112395Swnj 	tp = &dh11[minor(dev)];
31213Sbill 	(*linesw[tp->t_line].l_write)(tp);
31313Sbill }
31413Sbill 
31513Sbill /*
31613Sbill  * DH11 receiver interrupt.
31713Sbill  */
3182395Swnj dhrint(dh)
3192395Swnj 	int dh;
32013Sbill {
32113Sbill 	register struct tty *tp;
3222395Swnj 	register c;
3232479Swnj 	register struct dhdevice *addr;
324117Sbill 	register struct tty *tp0;
325*2974Swnj 	register struct uba_device *ui;
3262924Swnj 	int overrun = 0;
32713Sbill 
3282395Swnj 	ui = dhinfo[dh];
3292479Swnj 	if (ui == 0 || ui->ui_alive == 0)
3302479Swnj 		return;
3312479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3322468Swnj 	tp0 = &dh11[dh<<4];
3332468Swnj 	/*
3342468Swnj 	 * Loop fetching characters from the silo for this
3352468Swnj 	 * dh until there are no more in the silo.
3362468Swnj 	 */
3372468Swnj 	while ((c = addr->dhrcr) < 0) {
3382468Swnj 		tp = tp0 + ((c>>8)&0xf);
3392468Swnj 		if ((tp->t_state&ISOPEN)==0) {
34013Sbill 			wakeup((caddr_t)tp);
34113Sbill 			continue;
34213Sbill 		}
3432468Swnj 		if (c & DH_PE)
34413Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
34513Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
34613Sbill 				continue;
3472924Swnj 		if ((c & DH_DO) && overrun == 0) {
3482924Swnj 			printf("dh%d: silo overflow\n", dh);
3492924Swnj 			overrun = 1;
3502924Swnj 		}
3512468Swnj 		if (c & DH_FE)
3522468Swnj 			/*
3532468Swnj 			 * At framing error (break) generate
3542468Swnj 			 * a null (in raw mode, for getty), or a
3552468Swnj 			 * interrupt (in cooked/cbreak mode).
3562468Swnj 			 */
35713Sbill 			if (tp->t_flags&RAW)
3582468Swnj 				c = 0;
35913Sbill 			else
360184Sbill 				c = tun.t_intrc;
3612730Swnj #if NBK > 0
362139Sbill 		if (tp->t_line == NETLDISC) {
363117Sbill 			c &= 0177;
364168Sbill 			BKINPUT(c, tp);
365117Sbill 		} else
3662730Swnj #endif
3672468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
36813Sbill 	}
36913Sbill }
37013Sbill 
37113Sbill /*
3722468Swnj  * Ioctl for DH11.
37313Sbill  */
37413Sbill /*ARGSUSED*/
37513Sbill dhioctl(dev, cmd, addr, flag)
3762395Swnj 	caddr_t addr;
37713Sbill {
37813Sbill 	register struct tty *tp;
3792395Swnj 	register unit = minor(dev);
38013Sbill 
3812395Swnj 	tp = &dh11[unit];
382113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
3832468Swnj 	if (cmd == 0)
384113Sbill 		return;
3851895Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
3862468Swnj 		if (cmd==TIOCSETP || cmd==TIOCSETN)
3872395Swnj 			dhparam(unit);
388168Sbill 	} else switch(cmd) {
389168Sbill 	case TIOCSBRK:
3902479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
391168Sbill 		break;
392168Sbill 	case TIOCCBRK:
3932479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
394168Sbill 		break;
395168Sbill 	case TIOCSDTR:
3962479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
397168Sbill 		break;
398168Sbill 	case TIOCCDTR:
3992479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
400168Sbill 		break;
401168Sbill 	default:
40213Sbill 		u.u_error = ENOTTY;
403168Sbill 	}
40413Sbill }
40513Sbill 
40613Sbill /*
40713Sbill  * Set parameters from open or stty into the DH hardware
40813Sbill  * registers.
40913Sbill  */
4102395Swnj dhparam(unit)
4112395Swnj 	register int unit;
41213Sbill {
41313Sbill 	register struct tty *tp;
4142479Swnj 	register struct dhdevice *addr;
4152395Swnj 	register int lpar;
416300Sbill 	int s;
41713Sbill 
4182395Swnj 	tp = &dh11[unit];
4192479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4202468Swnj 	/*
4212468Swnj 	 * Block interrupts so parameters will be set
4222468Swnj 	 * before the line interrupts.
4232468Swnj 	 */
424300Sbill 	s = spl5();
4252468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
42613Sbill 	if ((tp->t_ispeed)==0) {
42713Sbill 		tp->t_state |= HUPCLS;
4282479Swnj 		dmctl(unit, DML_OFF, DMSET);
42913Sbill 		return;
43013Sbill 	}
4312395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4322468Swnj 	if ((tp->t_ispeed) == B134)
4332395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4342312Skre 	else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
4352395Swnj 		lpar |= BITS8;
43613Sbill 	else
4372395Swnj 		lpar |= BITS7|PENABLE;
43813Sbill 	if ((tp->t_flags&EVENP) == 0)
4392395Swnj 		lpar |= OPAR;
4402468Swnj 	if ((tp->t_ospeed) == B110)
4412395Swnj 		lpar |= TWOSB;
4422395Swnj 	addr->dhlpr = lpar;
443300Sbill 	splx(s);
44413Sbill }
44513Sbill 
44613Sbill /*
44713Sbill  * DH11 transmitter interrupt.
44813Sbill  * Restart each line which used to be active but has
44913Sbill  * terminated transmission since the last interrupt.
45013Sbill  */
4512395Swnj dhxint(dh)
4522395Swnj 	int dh;
45313Sbill {
45413Sbill 	register struct tty *tp;
4552479Swnj 	register struct dhdevice *addr;
45613Sbill 	short ttybit, bar, *sbar;
457*2974Swnj 	register struct uba_device *ui;
4582468Swnj 	register int unit;
4592605Swnj 	u_short cntr;
46013Sbill 
4612395Swnj 	ui = dhinfo[dh];
4622479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4632456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4642456Swnj 		addr->un.dhcsr |= DH_CNI;
4652924Swnj 		printf("dh%d: NXM\n", dh);
466105Sbill 	}
4672395Swnj 	sbar = &dhsar[dh];
46813Sbill 	bar = *sbar & ~addr->dhbar;
4692395Swnj 	unit = dh * 16; ttybit = 1;
4702468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4712468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4722468Swnj 		if (bar & ttybit) {
47313Sbill 			*sbar &= ~ttybit;
47413Sbill 			bar &= ~ttybit;
4752395Swnj 			tp = &dh11[unit];
476113Sbill 			tp->t_state &= ~BUSY;
477113Sbill 			if (tp->t_state&FLUSH)
478113Sbill 				tp->t_state &= ~FLUSH;
479113Sbill 			else {
4802456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4812468Swnj 				/*
4822468Swnj 				 * Do arithmetic in a short to make up
4832468Swnj 				 * for lost 16&17 bits.
4842468Swnj 				 */
4852605Swnj 				cntr = addr->dhcar -
4862468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4872605Swnj 				ndflush(&tp->t_outq, cntr);
488113Sbill 			}
489113Sbill 			if (tp->t_line)
49013Sbill 				(*linesw[tp->t_line].l_start)(tp);
491113Sbill 			else
49213Sbill 				dhstart(tp);
49313Sbill 		}
49413Sbill 	}
49513Sbill }
49613Sbill 
49713Sbill /*
49813Sbill  * Start (restart) transmission on the given DH11 line.
49913Sbill  */
50013Sbill dhstart(tp)
5012395Swnj 	register struct tty *tp;
50213Sbill {
5032479Swnj 	register struct dhdevice *addr;
5042468Swnj 	register int car, dh, unit, nch;
5052395Swnj 	int s;
50613Sbill 
5072468Swnj 	unit = minor(tp->t_dev);
5082468Swnj 	dh = unit >> 4;
5092468Swnj 	unit &= 0xf;
5102479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5112468Swnj 
51213Sbill 	/*
5132468Swnj 	 * Must hold interrupts in following code to prevent
5142468Swnj 	 * state of the tp from changing.
51513Sbill 	 */
51613Sbill 	s = spl5();
5172468Swnj 	/*
5182468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5192468Swnj 	 */
52013Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
52113Sbill 		goto out;
5222468Swnj 	/*
5232468Swnj 	 * If there are sleepers, and output has drained below low
5242468Swnj 	 * water mark, wake up the sleepers.
5252468Swnj 	 */
5262395Swnj 	if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
52713Sbill 		tp->t_state &= ~ASLEEP;
52813Sbill 		if (tp->t_chan)
529168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
530168Sbill 		else
53113Sbill 			wakeup((caddr_t)&tp->t_outq);
53213Sbill 	}
5332468Swnj 	/*
5342468Swnj 	 * Now restart transmission unless the output queue is
5352468Swnj 	 * empty.
5362468Swnj 	 */
53713Sbill 	if (tp->t_outq.c_cc == 0)
53813Sbill 		goto out;
5392395Swnj 	if (tp->t_flags & RAW)
54013Sbill 		nch = ndqb(&tp->t_outq, 0);
5412395Swnj 	else {
54213Sbill 		nch = ndqb(&tp->t_outq, 0200);
5432468Swnj 		/*
5442468Swnj 		 * If first thing on queue is a delay process it.
5452468Swnj 		 */
54613Sbill 		if (nch == 0) {
54713Sbill 			nch = getc(&tp->t_outq);
5482468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
54913Sbill 			tp->t_state |= TIMEOUT;
55013Sbill 			goto out;
55113Sbill 		}
55213Sbill 	}
5532468Swnj 	/*
5542468Swnj 	 * If characters to transmit, restart transmission.
5552468Swnj 	 */
55613Sbill 	if (nch) {
5572468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5582468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5592468Swnj 		unit = 1 << unit;
5602468Swnj 		dhsar[dh] |= unit;
5612468Swnj 		addr->dhcar = car;
56213Sbill 		addr->dhbcr = -nch;
5632468Swnj 		addr->dhbar |= unit;
56413Sbill 		tp->t_state |= BUSY;
56513Sbill 	}
5662395Swnj out:
56713Sbill 	splx(s);
56813Sbill }
56913Sbill 
57013Sbill /*
5712468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
57213Sbill  */
57313Sbill /*ARGSUSED*/
57413Sbill dhstop(tp, flag)
5752468Swnj 	register struct tty *tp;
57613Sbill {
5772479Swnj 	register struct dhdevice *addr;
5782395Swnj 	register int unit, s;
57913Sbill 
5802479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5812468Swnj 	/*
5822468Swnj 	 * Block input/output interrupts while messing with state.
5832468Swnj 	 */
5842468Swnj 	s = spl5();
585113Sbill 	if (tp->t_state & BUSY) {
5862468Swnj 		/*
5872468Swnj 		 * Device is transmitting; stop output
5882468Swnj 		 * by selecting the line and setting the byte
5892468Swnj 		 * count to -1.  We will clean up later
5902468Swnj 		 * by examining the address where the dh stopped.
5912468Swnj 		 */
5922395Swnj 		unit = minor(tp->t_dev);
5932456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
59413Sbill 		if ((tp->t_state&TTSTOP)==0)
59513Sbill 			tp->t_state |= FLUSH;
596113Sbill 		addr->dhbcr = -1;
597113Sbill 	}
59813Sbill 	splx(s);
59913Sbill }
60013Sbill 
601168Sbill /*
602280Sbill  * Reset state of driver if UBA reset was necessary.
603280Sbill  * Reset the csrl and lpr registers on open lines, and
604280Sbill  * restart transmitters.
605280Sbill  */
6062395Swnj dhreset(uban)
6072468Swnj 	int uban;
608280Sbill {
6092395Swnj 	register int dh, unit;
610280Sbill 	register struct tty *tp;
611*2974Swnj 	register struct uba_device *ui;
6122421Skre 	int i;
613280Sbill 
6142421Skre 	if (dh_ubinfo[uban] == 0)
6152421Skre 		return;
6162421Skre 	ubarelse(uban, &dh_ubinfo[uban]);
6172421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6182770Swnj 	    512+nclist*sizeof (struct cblock), 0);
6192421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
6202395Swnj 	dh = 0;
6212643Swnj 	for (dh = 0; dh < NDH; dh++) {
6222421Skre 		ui = dhinfo[dh];
6232421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6242421Skre 			continue;
6252924Swnj 		printf(" dh%d", dh);
6262479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
6272479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
6282421Skre 		unit = dh * 16;
6292421Skre 		for (i = 0; i < 16; i++) {
6302421Skre 			tp = &dh11[unit];
6312421Skre 			if (tp->t_state & (ISOPEN|WOPEN)) {
6322421Skre 				dhparam(unit);
6332479Swnj 				dmctl(unit, DML_ON, DMSET);
6342421Skre 				tp->t_state &= ~BUSY;
6352421Skre 				dhstart(tp);
6362421Skre 			}
6372421Skre 			unit++;
638300Sbill 		}
639300Sbill 	}
640300Sbill 	dhtimer();
641280Sbill }
6422395Swnj 
6432468Swnj /*
6442468Swnj  * At software clock interrupt time or after a UNIBUS reset
6452468Swnj  * empty all the dh silos.
6462468Swnj  */
6472456Swnj dhtimer()
6482456Swnj {
6492456Swnj 	register int dh;
6502456Swnj 
6512643Swnj 	for (dh = 0; dh < NDH; dh++)
6522456Swnj 		dhrint(dh);
6532456Swnj }
6542456Swnj 
6552468Swnj /*
6562479Swnj  * Turn on the line associated with dh dev.
6572468Swnj  */
6582468Swnj dmopen(dev)
6592468Swnj 	dev_t dev;
6602468Swnj {
6612468Swnj 	register struct tty *tp;
6622468Swnj 	register struct dmdevice *addr;
663*2974Swnj 	register struct uba_device *ui;
6642468Swnj 	register int unit;
6652468Swnj 	register int dm;
6662468Swnj 
6672468Swnj 	unit = minor(dev);
6682479Swnj 	dm = unit >> 4;
6692468Swnj 	tp = &dh11[unit];
6702566Swnj 	unit &= 0xf;
6712643Swnj 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
6722566Swnj 	    (dhsoftCAR[dm]&(1<<unit))) {
6732468Swnj 		tp->t_state |= CARR_ON;
6742468Swnj 		return;
6752468Swnj 	}
6762468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6772468Swnj 	spl5();
6782479Swnj 	addr->dmcsr &= ~DM_SE;
6792479Swnj 	while (addr->dmcsr & DM_BUSY)
6802468Swnj 		;
6812566Swnj 	addr->dmcsr = unit;
6822479Swnj 	addr->dmlstat = DML_ON;
6832479Swnj 	if (addr->dmlstat&DML_CAR)
6842468Swnj 		tp->t_state |= CARR_ON;
6852479Swnj 	addr->dmcsr = DH_IE|DM_SE;
6862468Swnj 	while ((tp->t_state&CARR_ON)==0)
6872468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
6882468Swnj 	spl0();
6892468Swnj }
6902468Swnj 
6912468Swnj /*
6922468Swnj  * Dump control bits into the DM registers.
6932468Swnj  */
6942468Swnj dmctl(dev, bits, how)
6952468Swnj 	dev_t dev;
6962468Swnj 	int bits, how;
6972468Swnj {
698*2974Swnj 	register struct uba_device *ui;
6992468Swnj 	register struct dmdevice *addr;
7002468Swnj 	register int unit, s;
7012468Swnj 	int dm;
7022468Swnj 
7032468Swnj 	unit = minor(dev);
7042468Swnj 	dm = unit >> 4;
7052468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7062468Swnj 		return;
7072468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7082468Swnj 	s = spl5();
7092479Swnj 	addr->dmcsr &= ~DM_SE;
7102479Swnj 	while (addr->dmcsr & DM_BUSY)
7112468Swnj 		;
7122468Swnj 	addr->dmcsr = unit & 0xf;
7132468Swnj 	switch(how) {
7142468Swnj 	case DMSET:
7152468Swnj 		addr->dmlstat = bits;
7162468Swnj 		break;
7172468Swnj 	case DMBIS:
7182468Swnj 		addr->dmlstat |= bits;
7192468Swnj 		break;
7202468Swnj 	case DMBIC:
7212468Swnj 		addr->dmlstat &= ~bits;
7222468Swnj 		break;
7232468Swnj 	}
7242479Swnj 	addr->dmcsr = DH_IE|DM_SE;
7252468Swnj 	splx(s);
7262468Swnj }
7272468Swnj 
7282468Swnj /*
7292468Swnj  * DM11 interrupt; deal with carrier transitions.
7302468Swnj  */
7312468Swnj dmintr(dm)
7322468Swnj 	register int dm;
7332468Swnj {
734*2974Swnj 	register struct uba_device *ui;
7352468Swnj 	register struct tty *tp;
7362468Swnj 	register struct dmdevice *addr;
7372468Swnj 
7382468Swnj 	ui = dminfo[dm];
7392479Swnj 	if (ui == 0)
7402479Swnj 		return;
7412468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7422479Swnj 	if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CF) {
7432468Swnj 		tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
7442468Swnj 		wakeup((caddr_t)&tp->t_rawq);
7452468Swnj 		if ((tp->t_state&WOPEN)==0 &&
7462468Swnj 		    (tp->t_local&LMDMBUF)) {
7472479Swnj 			if (addr->dmlstat & DML_CAR) {
7482468Swnj 				tp->t_state &= ~TTSTOP;
7492468Swnj 				ttstart(tp);
7502468Swnj 			} else if ((tp->t_state&TTSTOP) == 0) {
7512468Swnj 				tp->t_state |= TTSTOP;
7522468Swnj 				dhstop(tp, 0);
7532468Swnj 			}
7542479Swnj 		} else if ((addr->dmlstat&DML_CAR)==0) {
7552468Swnj 			if ((tp->t_state&WOPEN)==0 &&
7562468Swnj 			    (tp->t_local&LNOHANG)==0) {
7572468Swnj 				gsignal(tp->t_pgrp, SIGHUP);
7582468Swnj 				gsignal(tp->t_pgrp, SIGCONT);
7592468Swnj 				addr->dmlstat = 0;
7602468Swnj 				flushtty(tp, FREAD|FWRITE);
7612468Swnj 			}
7622468Swnj 			tp->t_state &= ~CARR_ON;
7632468Swnj 		} else
7642468Swnj 			tp->t_state |= CARR_ON;
7652479Swnj 		addr->dmcsr = DH_IE|DM_SE;
7662468Swnj 	}
7672468Swnj }
7682625Swnj #endif
769