xref: /csrg-svn/sys/vax/uba/dh.c (revision 3997)
1*3997Sroot /*	dh.c	4.37	81/07/10	*/
213Sbill 
31934Swnj #include "dh.h"
42643Swnj #if NDH > 0
513Sbill /*
62479Swnj  * DH-11/DM-11 driver
713Sbill  */
82730Swnj #include "bk.h"
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"
172566Swnj #include "../h/vm.h"
182974Swnj #include "../h/ubareg.h"
192974Swnj #include "../h/ubavar.h"
20113Sbill #include "../h/bk.h"
211561Sbill #include "../h/clist.h"
221786Sbill #include "../h/mx.h"
232468Swnj #include "../h/file.h"
2413Sbill 
252468Swnj /*
262479Swnj  * Definition of the driver for the auto-configuration program.
272479Swnj  * There is one definition for the dh and one for the dm.
282468Swnj  */
292605Swnj int	dhprobe(), dhattach(), dhrint(), dhxint();
302974Swnj struct	uba_device *dhinfo[NDH];
312395Swnj u_short	dhstd[] = { 0 };
322395Swnj struct	uba_driver dhdriver =
332605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
342395Swnj 
352605Swnj int	dmprobe(), dmattach(), dmintr();
362974Swnj struct	uba_device *dminfo[NDH];
372479Swnj u_short	dmstd[] = { 0 };
382479Swnj struct	uba_driver dmdriver =
392605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
4013Sbill 
412479Swnj struct dhdevice
422479Swnj {
432479Swnj 	union {
442479Swnj 		short	dhcsr;		/* control-status register */
452479Swnj 		char	dhcsrl;		/* low byte for line select */
462479Swnj 	} un;
472479Swnj 	short	dhrcr;			/* receive character register */
482479Swnj 	short	dhlpr;			/* line parameter register */
492479Swnj 	u_short dhcar;			/* current address register */
502479Swnj 	short	dhbcr;			/* byte count register */
512479Swnj 	u_short	dhbar;			/* buffer active register */
522479Swnj 	short	dhbreak;		/* break control register */
532479Swnj 	short	dhsilo;			/* silo status register */
542479Swnj };
5513Sbill 
562456Swnj /* Bits in dhcsr */
572456Swnj #define	DH_TI	0100000		/* transmit interrupt */
582456Swnj #define	DH_SI	0040000		/* storage interrupt */
592456Swnj #define	DH_TIE	0020000		/* transmit interrupt enable */
602456Swnj #define	DH_SIE	0010000		/* storage interrupt enable */
612456Swnj #define	DH_MC	0004000		/* master clear */
622456Swnj #define	DH_NXM	0002000		/* non-existant memory */
632456Swnj #define	DH_MM	0001000		/* maintenance mode */
642456Swnj #define	DH_CNI	0000400		/* clear non-existant memory interrupt */
652456Swnj #define	DH_RI	0000200		/* receiver interrupt */
662456Swnj #define	DH_RIE	0000100		/* receiver interrupt enable */
6713Sbill 
682479Swnj /* Bits in dhlpr */
692479Swnj #define	BITS6	01
702479Swnj #define	BITS7	02
712479Swnj #define	BITS8	03
722479Swnj #define	TWOSB	04
732479Swnj #define	PENABLE	020
742479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */
752479Swnj #define	OPAR	040
762479Swnj #define	HDUPLX	040000
772479Swnj 
783441Sroot #if NBK == 0
793441Sroot #define	DH_IE	(DH_TIE|DH_RIE)
803441Sroot #else
812456Swnj #define	DH_IE	(DH_TIE|DH_SIE|DH_RIE)
823441Sroot #endif
832456Swnj 
842456Swnj /* Bits in dhrcr */
852479Swnj #define	DH_PE		0010000		/* parity error */
862479Swnj #define	DH_FE		0020000		/* framing error */
872479Swnj #define	DH_DO		0040000		/* data overrun */
882456Swnj 
892479Swnj struct dmdevice
902479Swnj {
912479Swnj 	short	dmcsr;		/* control status register */
922479Swnj 	short	dmlstat;	/* line status register */
932479Swnj 	short	dmpad1[2];
942479Swnj };
952479Swnj 
962479Swnj /* bits in dm csr */
972479Swnj #define	DM_RF		0100000		/* ring flag */
982479Swnj #define	DM_CF		0040000		/* carrier flag */
992479Swnj #define	DM_CTS		0020000		/* clear to send */
1002479Swnj #define	DM_SRF		0010000		/* secondary receive flag */
1012479Swnj #define	DM_CS		0004000		/* clear scan */
1022479Swnj #define	DM_CM		0002000		/* clear multiplexor */
1032479Swnj #define	DM_MM		0001000		/* maintenance mode */
1042479Swnj #define	DM_STP		0000400		/* step */
1052479Swnj #define	DM_DONE		0000200		/* scanner is done */
1062479Swnj #define	DM_IE		0000100		/* interrupt enable */
1072479Swnj #define	DM_SE		0000040		/* scan enable */
1082479Swnj #define	DM_BUSY		0000020		/* scan busy */
1092479Swnj 
1102479Swnj /* bits in dm lsr */
1112479Swnj #define	DML_RNG		0000200		/* ring */
1122479Swnj #define	DML_CAR		0000100		/* carrier detect */
1132479Swnj #define	DML_CTS		0000040		/* clear to send */
1142479Swnj #define	DML_SR		0000020		/* secondary receive */
1152479Swnj #define	DML_ST		0000010		/* secondary transmit */
1162479Swnj #define	DML_RTS		0000004		/* request to send */
1172479Swnj #define	DML_DTR		0000002		/* data terminal ready */
1182479Swnj #define	DML_LE		0000001		/* line enable */
1192479Swnj 
1203792Swnj #define	DML_ON		(DML_DTR|DML_RTS|DML_LE)
1212479Swnj #define	DML_OFF		(DML_LE)
1222479Swnj 
12313Sbill /*
1242479Swnj  * Local variables for the driver
12513Sbill  */
1262643Swnj short	dhsar[NDH];			/* software copy of last bar */
1272643Swnj short	dhsoftCAR[NDH];
12813Sbill 
1292643Swnj struct	tty dh11[NDH*16];
1302643Swnj int	ndh11	= NDH*16;
1312479Swnj int	dhact;				/* mask of active dh's */
1322479Swnj int	dhstart(), ttrstrt();
13313Sbill 
1342479Swnj /*
1352479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
1362479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1372479Swnj  * into an i/o space address for the DMA routine.
1382479Swnj  */
1392479Swnj int	dh_ubinfo[MAXNUBA];		/* info about allocated unibus map */
1402479Swnj int	cbase[MAXNUBA];			/* base address in unibus map */
1412479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
14213Sbill 
1432456Swnj /*
1442456Swnj  * Routine for configuration to force a dh to interrupt.
1452456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1462456Swnj  */
1472468Swnj /*ARGSUSED*/
1482605Swnj dhprobe(reg)
1492395Swnj 	caddr_t reg;
1502395Swnj {
1512468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1522479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1532395Swnj 
1542605Swnj #ifdef lint
1552605Swnj 	br = 0; cvec = br; br = cvec;
1562605Swnj #endif
1572696Swnj #ifndef notdef
1582566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1593441Sroot 	DELAY(25);
1602566Swnj 	dhaddr->un.dhcsr = 0;
1612566Swnj #else
1622456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1632456Swnj 	DELAY(5);
1642456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1652421Skre 	dhaddr->dhbcr = -1;
1662456Swnj 	dhaddr->dhcar = 0;
1672421Skre 	dhaddr->dhbar = 1;
1682456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1692421Skre 	dhaddr->un.dhcsr = 0;
1702456Swnj 	if (cvec && cvec != 0x200)
1712456Swnj 		cvec -= 4;		/* transmit -> receive */
1722482Swnj #endif
1732456Swnj 	return (1);
1742395Swnj }
1752395Swnj 
1762456Swnj /*
1772605Swnj  * Routine called to attach a dh.
1782456Swnj  */
1792605Swnj dhattach(ui)
1802974Swnj 	struct uba_device *ui;
1812395Swnj {
1822395Swnj 
1832566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1842395Swnj }
1852395Swnj 
18613Sbill /*
1872479Swnj  * Configuration routine to cause a dm to interrupt.
1882479Swnj  */
1892605Swnj dmprobe(reg)
1902605Swnj 	caddr_t reg;
1912479Swnj {
1922479Swnj 	register int br, vec;			/* value-result */
1932605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1942479Swnj 
1952605Swnj #ifdef lint
1963101Swnj 	br = 0; vec = br; br = vec;
1972605Swnj #endif
1982479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1992479Swnj 	DELAY(20);
2002479Swnj 	dmaddr->dmcsr = 0;
2012605Swnj 	return (1);
2022479Swnj }
2032479Swnj 
2042605Swnj /*ARGSUSED*/
2052605Swnj dmattach(ui)
2062974Swnj 	struct uba_device *ui;
2072479Swnj {
2082479Swnj 
2092479Swnj 	/* no local state to set up */
2102479Swnj }
2112479Swnj 
2122479Swnj /*
2132468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
2142468Swnj  * is the first dh on this uba.  Turn on this dh if this is
2152468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
21613Sbill  */
21713Sbill /*ARGSUSED*/
21813Sbill dhopen(dev, flag)
2192395Swnj 	dev_t dev;
22013Sbill {
22113Sbill 	register struct tty *tp;
2222395Swnj 	register int unit, dh;
2232479Swnj 	register struct dhdevice *addr;
2242974Swnj 	register struct uba_device *ui;
22513Sbill 	int s;
22613Sbill 
2272395Swnj 	unit = minor(dev);
2282395Swnj 	dh = unit >> 4;
2292643Swnj 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) {
23013Sbill 		u.u_error = ENXIO;
23113Sbill 		return;
23213Sbill 	}
2332395Swnj 	tp = &dh11[unit];
2342468Swnj 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
2352468Swnj 		u.u_error = EBUSY;
2362468Swnj 		return;
2372468Swnj 	}
2382479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
23913Sbill 	tp->t_addr = (caddr_t)addr;
24013Sbill 	tp->t_oproc = dhstart;
24113Sbill 	tp->t_iproc = NULL;
24213Sbill 	tp->t_state |= WOPEN;
2432468Swnj 	/*
2442468Swnj 	 * While setting up state for this uba and this dh,
2452468Swnj 	 * block uba resets which can clear the state.
2462468Swnj 	 */
2472468Swnj 	s = spl5();
2482421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
249717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
2502395Swnj 		dh_ubinfo[ui->ui_ubanum] =
2512421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2522770Swnj 			512+nclist*sizeof(struct cblock), 0);
2532456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
25413Sbill 	}
2552456Swnj 	if ((dhact&(1<<dh)) == 0) {
2562456Swnj 		addr->un.dhcsr |= DH_IE;
2572468Swnj 		dhact |= (1<<dh);
2583845Swnj #if NBK > 0
2592456Swnj 		addr->dhsilo = 16;
2603845Swnj #endif
2612456Swnj 	}
26213Sbill 	splx(s);
2632468Swnj 	/*
2642468Swnj 	 * If this is first open, initialze tty state to default.
2652468Swnj 	 */
26613Sbill 	if ((tp->t_state&ISOPEN) == 0) {
26713Sbill 		ttychars(tp);
268168Sbill 		if (tp->t_ispeed == 0) {
2692456Swnj 			tp->t_ispeed = B300;
2702456Swnj 			tp->t_ospeed = B300;
271168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
272168Sbill 		}
2732395Swnj 		dhparam(unit);
27413Sbill 	}
2752468Swnj 	/*
2762468Swnj 	 * Wait for carrier, then process line discipline specific open.
2772468Swnj 	 */
27813Sbill 	dmopen(dev);
2792395Swnj 	(*linesw[tp->t_line].l_open)(dev, tp);
28013Sbill }
28113Sbill 
28213Sbill /*
2832468Swnj  * Close a DH11 line, turning off the DM11.
28413Sbill  */
28513Sbill /*ARGSUSED*/
28613Sbill dhclose(dev, flag)
2872395Swnj 	dev_t dev;
2882395Swnj 	int flag;
28913Sbill {
29013Sbill 	register struct tty *tp;
2912395Swnj 	register unit;
29213Sbill 
2932395Swnj 	unit = minor(dev);
2942395Swnj 	tp = &dh11[unit];
29513Sbill 	(*linesw[tp->t_line].l_close)(tp);
2962479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
29713Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
2982479Swnj 		dmctl(unit, DML_OFF, DMSET);
29913Sbill 	ttyclose(tp);
30013Sbill }
30113Sbill 
30213Sbill dhread(dev)
3032395Swnj 	dev_t dev;
30413Sbill {
3052395Swnj 	register struct tty *tp;
30613Sbill 
3072395Swnj 	tp = &dh11[minor(dev)];
30813Sbill 	(*linesw[tp->t_line].l_read)(tp);
30913Sbill }
31013Sbill 
31113Sbill dhwrite(dev)
3122395Swnj 	dev_t dev;
31313Sbill {
3142395Swnj 	register struct tty *tp;
31513Sbill 
3162395Swnj 	tp = &dh11[minor(dev)];
31713Sbill 	(*linesw[tp->t_line].l_write)(tp);
31813Sbill }
31913Sbill 
32013Sbill /*
32113Sbill  * DH11 receiver interrupt.
32213Sbill  */
3232395Swnj dhrint(dh)
3242395Swnj 	int dh;
32513Sbill {
32613Sbill 	register struct tty *tp;
3272395Swnj 	register c;
3282479Swnj 	register struct dhdevice *addr;
329117Sbill 	register struct tty *tp0;
3302974Swnj 	register struct uba_device *ui;
3312924Swnj 	int overrun = 0;
33213Sbill 
3332395Swnj 	ui = dhinfo[dh];
3342479Swnj 	if (ui == 0 || ui->ui_alive == 0)
3352479Swnj 		return;
3362479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3372468Swnj 	tp0 = &dh11[dh<<4];
3382468Swnj 	/*
3392468Swnj 	 * Loop fetching characters from the silo for this
3402468Swnj 	 * dh until there are no more in the silo.
3412468Swnj 	 */
3422468Swnj 	while ((c = addr->dhrcr) < 0) {
3432468Swnj 		tp = tp0 + ((c>>8)&0xf);
3442468Swnj 		if ((tp->t_state&ISOPEN)==0) {
34513Sbill 			wakeup((caddr_t)tp);
34613Sbill 			continue;
34713Sbill 		}
3482468Swnj 		if (c & DH_PE)
34913Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
35013Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
35113Sbill 				continue;
3522924Swnj 		if ((c & DH_DO) && overrun == 0) {
3532924Swnj 			printf("dh%d: silo overflow\n", dh);
3542924Swnj 			overrun = 1;
3552924Swnj 		}
3562468Swnj 		if (c & DH_FE)
3572468Swnj 			/*
3582468Swnj 			 * At framing error (break) generate
3592468Swnj 			 * a null (in raw mode, for getty), or a
3602468Swnj 			 * interrupt (in cooked/cbreak mode).
3612468Swnj 			 */
36213Sbill 			if (tp->t_flags&RAW)
3632468Swnj 				c = 0;
36413Sbill 			else
365184Sbill 				c = tun.t_intrc;
3662730Swnj #if NBK > 0
367139Sbill 		if (tp->t_line == NETLDISC) {
368117Sbill 			c &= 0177;
369168Sbill 			BKINPUT(c, tp);
370117Sbill 		} else
3712730Swnj #endif
3722468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
37313Sbill 	}
37413Sbill }
37513Sbill 
37613Sbill /*
3772468Swnj  * Ioctl for DH11.
37813Sbill  */
37913Sbill /*ARGSUSED*/
38013Sbill dhioctl(dev, cmd, addr, flag)
3812395Swnj 	caddr_t addr;
38213Sbill {
38313Sbill 	register struct tty *tp;
3842395Swnj 	register unit = minor(dev);
38513Sbill 
3862395Swnj 	tp = &dh11[unit];
387113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
3882468Swnj 	if (cmd == 0)
389113Sbill 		return;
3901895Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
3912468Swnj 		if (cmd==TIOCSETP || cmd==TIOCSETN)
3922395Swnj 			dhparam(unit);
393168Sbill 	} else switch(cmd) {
394168Sbill 	case TIOCSBRK:
3952479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
396168Sbill 		break;
397168Sbill 	case TIOCCBRK:
3982479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
399168Sbill 		break;
400168Sbill 	case TIOCSDTR:
4012479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
402168Sbill 		break;
403168Sbill 	case TIOCCDTR:
4042479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
405168Sbill 		break;
406168Sbill 	default:
40713Sbill 		u.u_error = ENOTTY;
408168Sbill 	}
40913Sbill }
41013Sbill 
41113Sbill /*
41213Sbill  * Set parameters from open or stty into the DH hardware
41313Sbill  * registers.
41413Sbill  */
4152395Swnj dhparam(unit)
4162395Swnj 	register int unit;
41713Sbill {
41813Sbill 	register struct tty *tp;
4192479Swnj 	register struct dhdevice *addr;
4202395Swnj 	register int lpar;
421300Sbill 	int s;
42213Sbill 
4232395Swnj 	tp = &dh11[unit];
4242479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4252468Swnj 	/*
4262468Swnj 	 * Block interrupts so parameters will be set
4272468Swnj 	 * before the line interrupts.
4282468Swnj 	 */
429300Sbill 	s = spl5();
4302468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
43113Sbill 	if ((tp->t_ispeed)==0) {
43213Sbill 		tp->t_state |= HUPCLS;
4332479Swnj 		dmctl(unit, DML_OFF, DMSET);
43413Sbill 		return;
43513Sbill 	}
4362395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4372468Swnj 	if ((tp->t_ispeed) == B134)
4382395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4392312Skre 	else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
4402395Swnj 		lpar |= BITS8;
44113Sbill 	else
4422395Swnj 		lpar |= BITS7|PENABLE;
44313Sbill 	if ((tp->t_flags&EVENP) == 0)
4442395Swnj 		lpar |= OPAR;
4452468Swnj 	if ((tp->t_ospeed) == B110)
4462395Swnj 		lpar |= TWOSB;
4472395Swnj 	addr->dhlpr = lpar;
448300Sbill 	splx(s);
44913Sbill }
45013Sbill 
45113Sbill /*
45213Sbill  * DH11 transmitter interrupt.
45313Sbill  * Restart each line which used to be active but has
45413Sbill  * terminated transmission since the last interrupt.
45513Sbill  */
4562395Swnj dhxint(dh)
4572395Swnj 	int dh;
45813Sbill {
45913Sbill 	register struct tty *tp;
4602479Swnj 	register struct dhdevice *addr;
46113Sbill 	short ttybit, bar, *sbar;
4622974Swnj 	register struct uba_device *ui;
4632468Swnj 	register int unit;
4642605Swnj 	u_short cntr;
46513Sbill 
4662395Swnj 	ui = dhinfo[dh];
4672479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4682456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4692456Swnj 		addr->un.dhcsr |= DH_CNI;
4702924Swnj 		printf("dh%d: NXM\n", dh);
471105Sbill 	}
4722395Swnj 	sbar = &dhsar[dh];
47313Sbill 	bar = *sbar & ~addr->dhbar;
4742395Swnj 	unit = dh * 16; ttybit = 1;
4752468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4762468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4772468Swnj 		if (bar & ttybit) {
47813Sbill 			*sbar &= ~ttybit;
47913Sbill 			bar &= ~ttybit;
4802395Swnj 			tp = &dh11[unit];
481113Sbill 			tp->t_state &= ~BUSY;
482113Sbill 			if (tp->t_state&FLUSH)
483113Sbill 				tp->t_state &= ~FLUSH;
484113Sbill 			else {
4852456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4862468Swnj 				/*
4872468Swnj 				 * Do arithmetic in a short to make up
4882468Swnj 				 * for lost 16&17 bits.
4892468Swnj 				 */
4902605Swnj 				cntr = addr->dhcar -
4912468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4923101Swnj 				ndflush(&tp->t_outq, (int)cntr);
493113Sbill 			}
494113Sbill 			if (tp->t_line)
49513Sbill 				(*linesw[tp->t_line].l_start)(tp);
496113Sbill 			else
49713Sbill 				dhstart(tp);
49813Sbill 		}
49913Sbill 	}
50013Sbill }
50113Sbill 
50213Sbill /*
50313Sbill  * Start (restart) transmission on the given DH11 line.
50413Sbill  */
50513Sbill dhstart(tp)
5062395Swnj 	register struct tty *tp;
50713Sbill {
5082479Swnj 	register struct dhdevice *addr;
5092468Swnj 	register int car, dh, unit, nch;
5102395Swnj 	int s;
51113Sbill 
5122468Swnj 	unit = minor(tp->t_dev);
5132468Swnj 	dh = unit >> 4;
5142468Swnj 	unit &= 0xf;
5152479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5162468Swnj 
51713Sbill 	/*
5182468Swnj 	 * Must hold interrupts in following code to prevent
5192468Swnj 	 * state of the tp from changing.
52013Sbill 	 */
52113Sbill 	s = spl5();
5222468Swnj 	/*
5232468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5242468Swnj 	 */
52513Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
52613Sbill 		goto out;
5272468Swnj 	/*
5282468Swnj 	 * If there are sleepers, and output has drained below low
5292468Swnj 	 * water mark, wake up the sleepers.
5302468Swnj 	 */
5312395Swnj 	if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
53213Sbill 		tp->t_state &= ~ASLEEP;
53313Sbill 		if (tp->t_chan)
534168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
535168Sbill 		else
53613Sbill 			wakeup((caddr_t)&tp->t_outq);
53713Sbill 	}
5382468Swnj 	/*
5392468Swnj 	 * Now restart transmission unless the output queue is
5402468Swnj 	 * empty.
5412468Swnj 	 */
54213Sbill 	if (tp->t_outq.c_cc == 0)
54313Sbill 		goto out;
5443703Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT)
54513Sbill 		nch = ndqb(&tp->t_outq, 0);
5462395Swnj 	else {
54713Sbill 		nch = ndqb(&tp->t_outq, 0200);
5482468Swnj 		/*
5492468Swnj 		 * If first thing on queue is a delay process it.
5502468Swnj 		 */
55113Sbill 		if (nch == 0) {
55213Sbill 			nch = getc(&tp->t_outq);
5532468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
55413Sbill 			tp->t_state |= TIMEOUT;
55513Sbill 			goto out;
55613Sbill 		}
55713Sbill 	}
5582468Swnj 	/*
5592468Swnj 	 * If characters to transmit, restart transmission.
5602468Swnj 	 */
56113Sbill 	if (nch) {
5622468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5632468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5643586Sroot 		/*
5653586Sroot 		 * The following nonsense with short word
5663586Sroot 		 * is to make sure the dhbar |= word below
5673586Sroot 		 * is done with an interlocking bisw2 instruction.
5683586Sroot 		 */
5693586Sroot 		{ short word = 1 << unit;
5703586Sroot 		dhsar[dh] |= word;
5712468Swnj 		addr->dhcar = car;
57213Sbill 		addr->dhbcr = -nch;
5733586Sroot 		addr->dhbar |= word;
5743586Sroot 		}
57513Sbill 		tp->t_state |= BUSY;
57613Sbill 	}
5772395Swnj out:
57813Sbill 	splx(s);
57913Sbill }
58013Sbill 
58113Sbill /*
5822468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
58313Sbill  */
58413Sbill /*ARGSUSED*/
58513Sbill dhstop(tp, flag)
5862468Swnj 	register struct tty *tp;
58713Sbill {
5882479Swnj 	register struct dhdevice *addr;
5892395Swnj 	register int unit, s;
59013Sbill 
5912479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5922468Swnj 	/*
5932468Swnj 	 * Block input/output interrupts while messing with state.
5942468Swnj 	 */
5952468Swnj 	s = spl5();
596113Sbill 	if (tp->t_state & BUSY) {
5972468Swnj 		/*
5982468Swnj 		 * Device is transmitting; stop output
5992468Swnj 		 * by selecting the line and setting the byte
6002468Swnj 		 * count to -1.  We will clean up later
6012468Swnj 		 * by examining the address where the dh stopped.
6022468Swnj 		 */
6032395Swnj 		unit = minor(tp->t_dev);
6042456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
60513Sbill 		if ((tp->t_state&TTSTOP)==0)
60613Sbill 			tp->t_state |= FLUSH;
607113Sbill 		addr->dhbcr = -1;
608113Sbill 	}
60913Sbill 	splx(s);
61013Sbill }
61113Sbill 
612168Sbill /*
613280Sbill  * Reset state of driver if UBA reset was necessary.
614280Sbill  * Reset the csrl and lpr registers on open lines, and
615280Sbill  * restart transmitters.
616280Sbill  */
6172395Swnj dhreset(uban)
6182468Swnj 	int uban;
619280Sbill {
6202395Swnj 	register int dh, unit;
621280Sbill 	register struct tty *tp;
6222974Swnj 	register struct uba_device *ui;
6232421Skre 	int i;
624280Sbill 
6252421Skre 	if (dh_ubinfo[uban] == 0)
6262421Skre 		return;
6272421Skre 	ubarelse(uban, &dh_ubinfo[uban]);
6282421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6292770Swnj 	    512+nclist*sizeof (struct cblock), 0);
6302421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
6312395Swnj 	dh = 0;
6322643Swnj 	for (dh = 0; dh < NDH; dh++) {
6332421Skre 		ui = dhinfo[dh];
6342421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6352421Skre 			continue;
6362924Swnj 		printf(" dh%d", dh);
6372479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
6383852Swnj #if NBK > 0
6392479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
6403852Swnj #endif
6412421Skre 		unit = dh * 16;
6422421Skre 		for (i = 0; i < 16; i++) {
6432421Skre 			tp = &dh11[unit];
6442421Skre 			if (tp->t_state & (ISOPEN|WOPEN)) {
6452421Skre 				dhparam(unit);
6462479Swnj 				dmctl(unit, DML_ON, DMSET);
6472421Skre 				tp->t_state &= ~BUSY;
6482421Skre 				dhstart(tp);
6492421Skre 			}
6502421Skre 			unit++;
651300Sbill 		}
652300Sbill 	}
653300Sbill 	dhtimer();
654280Sbill }
6552395Swnj 
6562468Swnj /*
6572468Swnj  * At software clock interrupt time or after a UNIBUS reset
6582468Swnj  * empty all the dh silos.
6592468Swnj  */
6602456Swnj dhtimer()
6612456Swnj {
6622456Swnj 	register int dh;
6632456Swnj 
6642643Swnj 	for (dh = 0; dh < NDH; dh++)
6652456Swnj 		dhrint(dh);
6662456Swnj }
6672456Swnj 
6682468Swnj /*
6692479Swnj  * Turn on the line associated with dh dev.
6702468Swnj  */
6712468Swnj dmopen(dev)
6722468Swnj 	dev_t dev;
6732468Swnj {
6742468Swnj 	register struct tty *tp;
6752468Swnj 	register struct dmdevice *addr;
6762974Swnj 	register struct uba_device *ui;
6772468Swnj 	register int unit;
6782468Swnj 	register int dm;
6793792Swnj 	int s;
6802468Swnj 
6812468Swnj 	unit = minor(dev);
6822479Swnj 	dm = unit >> 4;
6832468Swnj 	tp = &dh11[unit];
6842566Swnj 	unit &= 0xf;
6852643Swnj 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
6862566Swnj 	    (dhsoftCAR[dm]&(1<<unit))) {
6872468Swnj 		tp->t_state |= CARR_ON;
6882468Swnj 		return;
6892468Swnj 	}
6902468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6913792Swnj 	s = spl5();
6922479Swnj 	addr->dmcsr &= ~DM_SE;
6932479Swnj 	while (addr->dmcsr & DM_BUSY)
6942468Swnj 		;
6952566Swnj 	addr->dmcsr = unit;
6962479Swnj 	addr->dmlstat = DML_ON;
6972479Swnj 	if (addr->dmlstat&DML_CAR)
6982468Swnj 		tp->t_state |= CARR_ON;
6993792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7002468Swnj 	while ((tp->t_state&CARR_ON)==0)
7012468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
7023792Swnj 	splx(s);
7032468Swnj }
7042468Swnj 
7052468Swnj /*
7062468Swnj  * Dump control bits into the DM registers.
7072468Swnj  */
7082468Swnj dmctl(dev, bits, how)
7092468Swnj 	dev_t dev;
7102468Swnj 	int bits, how;
7112468Swnj {
7122974Swnj 	register struct uba_device *ui;
7132468Swnj 	register struct dmdevice *addr;
7142468Swnj 	register int unit, s;
7152468Swnj 	int dm;
7162468Swnj 
7172468Swnj 	unit = minor(dev);
7182468Swnj 	dm = unit >> 4;
7192468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7202468Swnj 		return;
7212468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7222468Swnj 	s = spl5();
7232479Swnj 	addr->dmcsr &= ~DM_SE;
7242479Swnj 	while (addr->dmcsr & DM_BUSY)
7252468Swnj 		;
7262468Swnj 	addr->dmcsr = unit & 0xf;
7272468Swnj 	switch(how) {
7282468Swnj 	case DMSET:
7292468Swnj 		addr->dmlstat = bits;
7302468Swnj 		break;
7312468Swnj 	case DMBIS:
7322468Swnj 		addr->dmlstat |= bits;
7332468Swnj 		break;
7342468Swnj 	case DMBIC:
7352468Swnj 		addr->dmlstat &= ~bits;
7362468Swnj 		break;
7372468Swnj 	}
7383792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7392468Swnj 	splx(s);
7402468Swnj }
7412468Swnj 
7422468Swnj /*
7432468Swnj  * DM11 interrupt; deal with carrier transitions.
7442468Swnj  */
7452468Swnj dmintr(dm)
7462468Swnj 	register int dm;
7472468Swnj {
7482974Swnj 	register struct uba_device *ui;
7492468Swnj 	register struct tty *tp;
7502468Swnj 	register struct dmdevice *addr;
7512468Swnj 
7522468Swnj 	ui = dminfo[dm];
7532479Swnj 	if (ui == 0)
7542479Swnj 		return;
7552468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
756*3997Sroot 	if (addr->dmcsr&DM_DONE) {
757*3997Sroot 		if (addr->dmcsr&DM_CF) {
758*3997Sroot 			tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
759*3997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7602468Swnj 			if ((tp->t_state&WOPEN)==0 &&
761*3997Sroot 			    (tp->t_local&LMDMBUF)) {
762*3997Sroot 				if (addr->dmlstat & DML_CAR) {
763*3997Sroot 					tp->t_state &= ~TTSTOP;
764*3997Sroot 					ttstart(tp);
765*3997Sroot 				} else if ((tp->t_state&TTSTOP) == 0) {
766*3997Sroot 					tp->t_state |= TTSTOP;
767*3997Sroot 					dhstop(tp, 0);
768*3997Sroot 				}
769*3997Sroot 			} else if ((addr->dmlstat&DML_CAR)==0) {
770*3997Sroot 				if ((tp->t_state&WOPEN)==0 &&
771*3997Sroot 				    (tp->t_local&LNOHANG)==0) {
772*3997Sroot 					gsignal(tp->t_pgrp, SIGHUP);
773*3997Sroot 					gsignal(tp->t_pgrp, SIGCONT);
774*3997Sroot 					addr->dmlstat = 0;
775*3997Sroot 					flushtty(tp, FREAD|FWRITE);
776*3997Sroot 				}
777*3997Sroot 				tp->t_state &= ~CARR_ON;
778*3997Sroot 			} else
779*3997Sroot 				tp->t_state |= CARR_ON;
780*3997Sroot 		}
781*3997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7822468Swnj 	}
7832468Swnj }
7842625Swnj #endif
785