xref: /csrg-svn/sys/vax/uba/dh.c (revision 6615)
1*6615Ssam /*	dh.c	4.44	82/05/04	*/
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"
136185Ssam #include "../h/proc.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"
192974Swnj #include "../h/ubareg.h"
202974Swnj #include "../h/ubavar.h"
21113Sbill #include "../h/bk.h"
221561Sbill #include "../h/clist.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 
56*6615Ssam #ifndef	PORTSELECTOR
57*6615Ssam #define	ISPEED	B300
58*6615Ssam #define	IFLAGS	(EVENP|ODDP|ECHO)
59*6615Ssam #else
60*6615Ssam #define	ISPEED	B4800
61*6615Ssam #define	IFLAGS	(EVENP|ODDP)
62*6615Ssam #endif
63*6615Ssam 
642456Swnj /* Bits in dhcsr */
652456Swnj #define	DH_TI	0100000		/* transmit interrupt */
662456Swnj #define	DH_SI	0040000		/* storage interrupt */
672456Swnj #define	DH_TIE	0020000		/* transmit interrupt enable */
682456Swnj #define	DH_SIE	0010000		/* storage interrupt enable */
692456Swnj #define	DH_MC	0004000		/* master clear */
702456Swnj #define	DH_NXM	0002000		/* non-existant memory */
712456Swnj #define	DH_MM	0001000		/* maintenance mode */
722456Swnj #define	DH_CNI	0000400		/* clear non-existant memory interrupt */
732456Swnj #define	DH_RI	0000200		/* receiver interrupt */
742456Swnj #define	DH_RIE	0000100		/* receiver interrupt enable */
7513Sbill 
762479Swnj /* Bits in dhlpr */
772479Swnj #define	BITS6	01
782479Swnj #define	BITS7	02
792479Swnj #define	BITS8	03
802479Swnj #define	TWOSB	04
812479Swnj #define	PENABLE	020
822479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */
832479Swnj #define	OPAR	040
842479Swnj #define	HDUPLX	040000
852479Swnj 
862456Swnj #define	DH_IE	(DH_TIE|DH_SIE|DH_RIE)
872456Swnj 
882456Swnj /* Bits in dhrcr */
892479Swnj #define	DH_PE		0010000		/* parity error */
902479Swnj #define	DH_FE		0020000		/* framing error */
912479Swnj #define	DH_DO		0040000		/* data overrun */
922456Swnj 
932479Swnj struct dmdevice
942479Swnj {
952479Swnj 	short	dmcsr;		/* control status register */
962479Swnj 	short	dmlstat;	/* line status register */
972479Swnj 	short	dmpad1[2];
982479Swnj };
992479Swnj 
1002479Swnj /* bits in dm csr */
1012479Swnj #define	DM_RF		0100000		/* ring flag */
1022479Swnj #define	DM_CF		0040000		/* carrier flag */
1032479Swnj #define	DM_CTS		0020000		/* clear to send */
1042479Swnj #define	DM_SRF		0010000		/* secondary receive flag */
1052479Swnj #define	DM_CS		0004000		/* clear scan */
1062479Swnj #define	DM_CM		0002000		/* clear multiplexor */
1072479Swnj #define	DM_MM		0001000		/* maintenance mode */
1082479Swnj #define	DM_STP		0000400		/* step */
1092479Swnj #define	DM_DONE		0000200		/* scanner is done */
1102479Swnj #define	DM_IE		0000100		/* interrupt enable */
1112479Swnj #define	DM_SE		0000040		/* scan enable */
1122479Swnj #define	DM_BUSY		0000020		/* scan busy */
1132479Swnj 
1142479Swnj /* bits in dm lsr */
1152479Swnj #define	DML_RNG		0000200		/* ring */
1162479Swnj #define	DML_CAR		0000100		/* carrier detect */
1172479Swnj #define	DML_CTS		0000040		/* clear to send */
1182479Swnj #define	DML_SR		0000020		/* secondary receive */
1192479Swnj #define	DML_ST		0000010		/* secondary transmit */
1202479Swnj #define	DML_RTS		0000004		/* request to send */
1212479Swnj #define	DML_DTR		0000002		/* data terminal ready */
1222479Swnj #define	DML_LE		0000001		/* line enable */
1232479Swnj 
1243792Swnj #define	DML_ON		(DML_DTR|DML_RTS|DML_LE)
1252479Swnj #define	DML_OFF		(DML_LE)
1262479Swnj 
12713Sbill /*
1282479Swnj  * Local variables for the driver
12913Sbill  */
1302643Swnj short	dhsar[NDH];			/* software copy of last bar */
1312643Swnj short	dhsoftCAR[NDH];
13213Sbill 
1332643Swnj struct	tty dh11[NDH*16];
1342643Swnj int	ndh11	= NDH*16;
1352479Swnj int	dhact;				/* mask of active dh's */
1362479Swnj int	dhstart(), ttrstrt();
13713Sbill 
1382479Swnj /*
1392479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
1402479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1412479Swnj  * into an i/o space address for the DMA routine.
1422479Swnj  */
1432479Swnj int	dh_ubinfo[MAXNUBA];		/* info about allocated unibus map */
1442479Swnj int	cbase[MAXNUBA];			/* base address in unibus map */
1452479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
14613Sbill 
1472456Swnj /*
1482456Swnj  * Routine for configuration to force a dh to interrupt.
1492456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1502456Swnj  */
1512468Swnj /*ARGSUSED*/
1522605Swnj dhprobe(reg)
1532395Swnj 	caddr_t reg;
1542395Swnj {
1552468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1562479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1572395Swnj 
1582605Swnj #ifdef lint
1592605Swnj 	br = 0; cvec = br; br = cvec;
1604932Swnj 	dhrint(0); dhxint(0);
1612605Swnj #endif
1622696Swnj #ifndef notdef
1632566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1646380Swnj 	DELAY(1000);
1652566Swnj 	dhaddr->un.dhcsr = 0;
1662566Swnj #else
1672456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1682456Swnj 	DELAY(5);
1692456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1702421Skre 	dhaddr->dhbcr = -1;
1712456Swnj 	dhaddr->dhcar = 0;
1722421Skre 	dhaddr->dhbar = 1;
1732456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1742421Skre 	dhaddr->un.dhcsr = 0;
1752456Swnj 	if (cvec && cvec != 0x200)
1762456Swnj 		cvec -= 4;		/* transmit -> receive */
1772482Swnj #endif
1782456Swnj 	return (1);
1792395Swnj }
1802395Swnj 
1812456Swnj /*
1822605Swnj  * Routine called to attach a dh.
1832456Swnj  */
1842605Swnj dhattach(ui)
1852974Swnj 	struct uba_device *ui;
1862395Swnj {
1872395Swnj 
1882566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1892395Swnj }
1902395Swnj 
19113Sbill /*
1922479Swnj  * Configuration routine to cause a dm to interrupt.
1932479Swnj  */
1942605Swnj dmprobe(reg)
1952605Swnj 	caddr_t reg;
1962479Swnj {
1972479Swnj 	register int br, vec;			/* value-result */
1982605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1992479Swnj 
2002605Swnj #ifdef lint
2013101Swnj 	br = 0; vec = br; br = vec;
2026185Ssam 	dmintr(0);
2032605Swnj #endif
2042479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
2052479Swnj 	DELAY(20);
2062479Swnj 	dmaddr->dmcsr = 0;
2072605Swnj 	return (1);
2082479Swnj }
2092479Swnj 
2102605Swnj /*ARGSUSED*/
2112605Swnj dmattach(ui)
2122974Swnj 	struct uba_device *ui;
2132479Swnj {
2142479Swnj 
2152479Swnj 	/* no local state to set up */
2162479Swnj }
2172479Swnj 
2182479Swnj /*
2192468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
2202468Swnj  * is the first dh on this uba.  Turn on this dh if this is
2212468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
22213Sbill  */
22313Sbill /*ARGSUSED*/
22413Sbill dhopen(dev, flag)
2252395Swnj 	dev_t dev;
22613Sbill {
22713Sbill 	register struct tty *tp;
2282395Swnj 	register int unit, dh;
2292479Swnj 	register struct dhdevice *addr;
2302974Swnj 	register struct uba_device *ui;
23113Sbill 	int s;
23213Sbill 
2332395Swnj 	unit = minor(dev);
2342395Swnj 	dh = unit >> 4;
2352643Swnj 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) {
23613Sbill 		u.u_error = ENXIO;
23713Sbill 		return;
23813Sbill 	}
2392395Swnj 	tp = &dh11[unit];
2405406Swnj 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0) {
2412468Swnj 		u.u_error = EBUSY;
2422468Swnj 		return;
2432468Swnj 	}
2442479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
24513Sbill 	tp->t_addr = (caddr_t)addr;
24613Sbill 	tp->t_oproc = dhstart;
2475406Swnj 	tp->t_state |= TS_WOPEN;
2482468Swnj 	/*
2492468Swnj 	 * While setting up state for this uba and this dh,
2502468Swnj 	 * block uba resets which can clear the state.
2512468Swnj 	 */
2522468Swnj 	s = spl5();
2532421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
254717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
2552395Swnj 		dh_ubinfo[ui->ui_ubanum] =
2562421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2572770Swnj 			512+nclist*sizeof(struct cblock), 0);
2582456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
25913Sbill 	}
2602456Swnj 	if ((dhact&(1<<dh)) == 0) {
2612456Swnj 		addr->un.dhcsr |= DH_IE;
2622468Swnj 		dhact |= (1<<dh);
2632456Swnj 		addr->dhsilo = 16;
2642456Swnj 	}
26513Sbill 	splx(s);
2662468Swnj 	/*
2672468Swnj 	 * If this is first open, initialze tty state to default.
2682468Swnj 	 */
2695406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
27013Sbill 		ttychars(tp);
271*6615Ssam #ifndef PORTSELECTOR
272168Sbill 		if (tp->t_ispeed == 0) {
273*6615Ssam #endif
274*6615Ssam 			tp->t_ispeed = ISPEED;
275*6615Ssam 			tp->t_ospeed = ISPEED;
276*6615Ssam 			tp->t_flags = IFLAGS;
277*6615Ssam #ifndef PORTSELECTOR
278168Sbill 		}
279*6615Ssam #endif
2802395Swnj 		dhparam(unit);
28113Sbill 	}
2822468Swnj 	/*
2832468Swnj 	 * Wait for carrier, then process line discipline specific open.
2842468Swnj 	 */
28513Sbill 	dmopen(dev);
2862395Swnj 	(*linesw[tp->t_line].l_open)(dev, tp);
28713Sbill }
28813Sbill 
28913Sbill /*
2902468Swnj  * Close a DH11 line, turning off the DM11.
29113Sbill  */
29213Sbill /*ARGSUSED*/
29313Sbill dhclose(dev, flag)
2942395Swnj 	dev_t dev;
2952395Swnj 	int flag;
29613Sbill {
29713Sbill 	register struct tty *tp;
2982395Swnj 	register unit;
29913Sbill 
3002395Swnj 	unit = minor(dev);
3012395Swnj 	tp = &dh11[unit];
30213Sbill 	(*linesw[tp->t_line].l_close)(tp);
3032479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
3045406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
3052479Swnj 		dmctl(unit, DML_OFF, DMSET);
30613Sbill 	ttyclose(tp);
30713Sbill }
30813Sbill 
30913Sbill dhread(dev)
3102395Swnj 	dev_t dev;
31113Sbill {
3122395Swnj 	register struct tty *tp;
31313Sbill 
3142395Swnj 	tp = &dh11[minor(dev)];
31513Sbill 	(*linesw[tp->t_line].l_read)(tp);
31613Sbill }
31713Sbill 
31813Sbill dhwrite(dev)
3192395Swnj 	dev_t dev;
32013Sbill {
3212395Swnj 	register struct tty *tp;
32213Sbill 
3232395Swnj 	tp = &dh11[minor(dev)];
32413Sbill 	(*linesw[tp->t_line].l_write)(tp);
32513Sbill }
32613Sbill 
32713Sbill /*
32813Sbill  * DH11 receiver interrupt.
32913Sbill  */
3302395Swnj dhrint(dh)
3312395Swnj 	int dh;
33213Sbill {
33313Sbill 	register struct tty *tp;
3342395Swnj 	register c;
3352479Swnj 	register struct dhdevice *addr;
336117Sbill 	register struct tty *tp0;
3372974Swnj 	register struct uba_device *ui;
3382924Swnj 	int overrun = 0;
33913Sbill 
3402395Swnj 	ui = dhinfo[dh];
3412479Swnj 	if (ui == 0 || ui->ui_alive == 0)
3422479Swnj 		return;
3432479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3442468Swnj 	tp0 = &dh11[dh<<4];
3452468Swnj 	/*
3462468Swnj 	 * Loop fetching characters from the silo for this
3472468Swnj 	 * dh until there are no more in the silo.
3482468Swnj 	 */
3492468Swnj 	while ((c = addr->dhrcr) < 0) {
3502468Swnj 		tp = tp0 + ((c>>8)&0xf);
351*6615Ssam #ifndef PORTSELECTOR
3525406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
353*6615Ssam #else
354*6615Ssam 		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
355*6615Ssam #endif
35613Sbill 			wakeup((caddr_t)tp);
35713Sbill 			continue;
35813Sbill 		}
3592468Swnj 		if (c & DH_PE)
36013Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
36113Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
36213Sbill 				continue;
3632924Swnj 		if ((c & DH_DO) && overrun == 0) {
3642924Swnj 			printf("dh%d: silo overflow\n", dh);
3652924Swnj 			overrun = 1;
3662924Swnj 		}
3672468Swnj 		if (c & DH_FE)
3682468Swnj 			/*
3692468Swnj 			 * At framing error (break) generate
3702468Swnj 			 * a null (in raw mode, for getty), or a
3712468Swnj 			 * interrupt (in cooked/cbreak mode).
3722468Swnj 			 */
37313Sbill 			if (tp->t_flags&RAW)
3742468Swnj 				c = 0;
37513Sbill 			else
376184Sbill 				c = tun.t_intrc;
3772730Swnj #if NBK > 0
378139Sbill 		if (tp->t_line == NETLDISC) {
379117Sbill 			c &= 0177;
380168Sbill 			BKINPUT(c, tp);
381117Sbill 		} else
3822730Swnj #endif
3832468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
38413Sbill 	}
38513Sbill }
38613Sbill 
38713Sbill /*
3882468Swnj  * Ioctl for DH11.
38913Sbill  */
39013Sbill /*ARGSUSED*/
39113Sbill dhioctl(dev, cmd, addr, flag)
3922395Swnj 	caddr_t addr;
39313Sbill {
39413Sbill 	register struct tty *tp;
3952395Swnj 	register unit = minor(dev);
39613Sbill 
3972395Swnj 	tp = &dh11[unit];
398113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
3992468Swnj 	if (cmd == 0)
400113Sbill 		return;
4011895Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
4022468Swnj 		if (cmd==TIOCSETP || cmd==TIOCSETN)
4032395Swnj 			dhparam(unit);
404168Sbill 	} else switch(cmd) {
405168Sbill 	case TIOCSBRK:
4062479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
407168Sbill 		break;
408168Sbill 	case TIOCCBRK:
4092479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
410168Sbill 		break;
411168Sbill 	case TIOCSDTR:
4122479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
413168Sbill 		break;
414168Sbill 	case TIOCCDTR:
4152479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
416168Sbill 		break;
417168Sbill 	default:
41813Sbill 		u.u_error = ENOTTY;
419168Sbill 	}
42013Sbill }
42113Sbill 
42213Sbill /*
42313Sbill  * Set parameters from open or stty into the DH hardware
42413Sbill  * registers.
42513Sbill  */
4262395Swnj dhparam(unit)
4272395Swnj 	register int unit;
42813Sbill {
42913Sbill 	register struct tty *tp;
4302479Swnj 	register struct dhdevice *addr;
4312395Swnj 	register int lpar;
432300Sbill 	int s;
43313Sbill 
4342395Swnj 	tp = &dh11[unit];
4352479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4362468Swnj 	/*
4372468Swnj 	 * Block interrupts so parameters will be set
4382468Swnj 	 * before the line interrupts.
4392468Swnj 	 */
440300Sbill 	s = spl5();
4412468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
44213Sbill 	if ((tp->t_ispeed)==0) {
4435406Swnj 		tp->t_state |= TS_HUPCLS;
4442479Swnj 		dmctl(unit, DML_OFF, DMSET);
44513Sbill 		return;
44613Sbill 	}
4472395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4482468Swnj 	if ((tp->t_ispeed) == B134)
4492395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4502312Skre 	else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
4512395Swnj 		lpar |= BITS8;
45213Sbill 	else
4532395Swnj 		lpar |= BITS7|PENABLE;
45413Sbill 	if ((tp->t_flags&EVENP) == 0)
4552395Swnj 		lpar |= OPAR;
4562468Swnj 	if ((tp->t_ospeed) == B110)
4572395Swnj 		lpar |= TWOSB;
4582395Swnj 	addr->dhlpr = lpar;
459300Sbill 	splx(s);
46013Sbill }
46113Sbill 
46213Sbill /*
46313Sbill  * DH11 transmitter interrupt.
46413Sbill  * Restart each line which used to be active but has
46513Sbill  * terminated transmission since the last interrupt.
46613Sbill  */
4672395Swnj dhxint(dh)
4682395Swnj 	int dh;
46913Sbill {
47013Sbill 	register struct tty *tp;
4712479Swnj 	register struct dhdevice *addr;
47213Sbill 	short ttybit, bar, *sbar;
4732974Swnj 	register struct uba_device *ui;
4742468Swnj 	register int unit;
4752605Swnj 	u_short cntr;
47613Sbill 
4772395Swnj 	ui = dhinfo[dh];
4782479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4792456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4802456Swnj 		addr->un.dhcsr |= DH_CNI;
4812924Swnj 		printf("dh%d: NXM\n", dh);
482105Sbill 	}
4832395Swnj 	sbar = &dhsar[dh];
48413Sbill 	bar = *sbar & ~addr->dhbar;
4852395Swnj 	unit = dh * 16; ttybit = 1;
4862468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4872468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4882468Swnj 		if (bar & ttybit) {
48913Sbill 			*sbar &= ~ttybit;
49013Sbill 			bar &= ~ttybit;
4912395Swnj 			tp = &dh11[unit];
4925406Swnj 			tp->t_state &= ~TS_BUSY;
4935406Swnj 			if (tp->t_state&TS_FLUSH)
4945406Swnj 				tp->t_state &= ~TS_FLUSH;
495113Sbill 			else {
4962456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4972468Swnj 				/*
4982468Swnj 				 * Do arithmetic in a short to make up
4992468Swnj 				 * for lost 16&17 bits.
5002468Swnj 				 */
5012605Swnj 				cntr = addr->dhcar -
5022468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
5033101Swnj 				ndflush(&tp->t_outq, (int)cntr);
504113Sbill 			}
505113Sbill 			if (tp->t_line)
50613Sbill 				(*linesw[tp->t_line].l_start)(tp);
507113Sbill 			else
50813Sbill 				dhstart(tp);
50913Sbill 		}
51013Sbill 	}
51113Sbill }
51213Sbill 
51313Sbill /*
51413Sbill  * Start (restart) transmission on the given DH11 line.
51513Sbill  */
51613Sbill dhstart(tp)
5172395Swnj 	register struct tty *tp;
51813Sbill {
5192479Swnj 	register struct dhdevice *addr;
5202468Swnj 	register int car, dh, unit, nch;
5212395Swnj 	int s;
52213Sbill 
5232468Swnj 	unit = minor(tp->t_dev);
5242468Swnj 	dh = unit >> 4;
5252468Swnj 	unit &= 0xf;
5262479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5272468Swnj 
52813Sbill 	/*
5292468Swnj 	 * Must hold interrupts in following code to prevent
5302468Swnj 	 * state of the tp from changing.
53113Sbill 	 */
53213Sbill 	s = spl5();
5332468Swnj 	/*
5342468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5352468Swnj 	 */
5365406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
53713Sbill 		goto out;
5382468Swnj 	/*
5392468Swnj 	 * If there are sleepers, and output has drained below low
5402468Swnj 	 * water mark, wake up the sleepers.
5412468Swnj 	 */
5425406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
5435406Swnj 		if (tp->t_state&TS_ASLEEP) {
5445406Swnj 			tp->t_state &= ~TS_ASLEEP;
5455406Swnj 			wakeup((caddr_t)&tp->t_outq);
5465406Swnj 		}
5475406Swnj 		if (tp->t_wsel) {
5485406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5495406Swnj 			tp->t_wsel = 0;
5505406Swnj 			tp->t_state &= ~TS_WCOLL;
5515406Swnj 		}
55213Sbill 	}
5532468Swnj 	/*
5542468Swnj 	 * Now restart transmission unless the output queue is
5552468Swnj 	 * empty.
5562468Swnj 	 */
55713Sbill 	if (tp->t_outq.c_cc == 0)
55813Sbill 		goto out;
5593703Sroot 	if (tp->t_flags&RAW || tp->t_local&LLITOUT)
56013Sbill 		nch = ndqb(&tp->t_outq, 0);
5612395Swnj 	else {
56213Sbill 		nch = ndqb(&tp->t_outq, 0200);
5632468Swnj 		/*
5642468Swnj 		 * If first thing on queue is a delay process it.
5652468Swnj 		 */
56613Sbill 		if (nch == 0) {
56713Sbill 			nch = getc(&tp->t_outq);
5682468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5695406Swnj 			tp->t_state |= TS_TIMEOUT;
57013Sbill 			goto out;
57113Sbill 		}
57213Sbill 	}
5732468Swnj 	/*
5742468Swnj 	 * If characters to transmit, restart transmission.
5752468Swnj 	 */
57613Sbill 	if (nch) {
5772468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5782468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5793586Sroot 		/*
5803586Sroot 		 * The following nonsense with short word
5813586Sroot 		 * is to make sure the dhbar |= word below
5823586Sroot 		 * is done with an interlocking bisw2 instruction.
5833586Sroot 		 */
5843586Sroot 		{ short word = 1 << unit;
5853586Sroot 		dhsar[dh] |= word;
5862468Swnj 		addr->dhcar = car;
58713Sbill 		addr->dhbcr = -nch;
5883586Sroot 		addr->dhbar |= word;
5893586Sroot 		}
5905406Swnj 		tp->t_state |= TS_BUSY;
59113Sbill 	}
5922395Swnj out:
59313Sbill 	splx(s);
59413Sbill }
59513Sbill 
59613Sbill /*
5972468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
59813Sbill  */
59913Sbill /*ARGSUSED*/
60013Sbill dhstop(tp, flag)
6012468Swnj 	register struct tty *tp;
60213Sbill {
6032479Swnj 	register struct dhdevice *addr;
6042395Swnj 	register int unit, s;
60513Sbill 
6062479Swnj 	addr = (struct dhdevice *)tp->t_addr;
6072468Swnj 	/*
6082468Swnj 	 * Block input/output interrupts while messing with state.
6092468Swnj 	 */
6102468Swnj 	s = spl5();
6115406Swnj 	if (tp->t_state & TS_BUSY) {
6122468Swnj 		/*
6132468Swnj 		 * Device is transmitting; stop output
6142468Swnj 		 * by selecting the line and setting the byte
6152468Swnj 		 * count to -1.  We will clean up later
6162468Swnj 		 * by examining the address where the dh stopped.
6172468Swnj 		 */
6182395Swnj 		unit = minor(tp->t_dev);
6192456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
6205406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
6215406Swnj 			tp->t_state |= TS_FLUSH;
622113Sbill 		addr->dhbcr = -1;
623113Sbill 	}
62413Sbill 	splx(s);
62513Sbill }
62613Sbill 
627168Sbill /*
628280Sbill  * Reset state of driver if UBA reset was necessary.
629280Sbill  * Reset the csrl and lpr registers on open lines, and
630280Sbill  * restart transmitters.
631280Sbill  */
6322395Swnj dhreset(uban)
6332468Swnj 	int uban;
634280Sbill {
6352395Swnj 	register int dh, unit;
636280Sbill 	register struct tty *tp;
6372974Swnj 	register struct uba_device *ui;
6382421Skre 	int i;
639280Sbill 
6402421Skre 	if (dh_ubinfo[uban] == 0)
6412421Skre 		return;
6422421Skre 	ubarelse(uban, &dh_ubinfo[uban]);
6432421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6442770Swnj 	    512+nclist*sizeof (struct cblock), 0);
6452421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
6462395Swnj 	dh = 0;
6472643Swnj 	for (dh = 0; dh < NDH; dh++) {
6482421Skre 		ui = dhinfo[dh];
6492421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6502421Skre 			continue;
6512924Swnj 		printf(" dh%d", dh);
6522479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
6532479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
6542421Skre 		unit = dh * 16;
6552421Skre 		for (i = 0; i < 16; i++) {
6562421Skre 			tp = &dh11[unit];
6575406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6582421Skre 				dhparam(unit);
6592479Swnj 				dmctl(unit, DML_ON, DMSET);
6605406Swnj 				tp->t_state &= ~TS_BUSY;
6612421Skre 				dhstart(tp);
6622421Skre 			}
6632421Skre 			unit++;
664300Sbill 		}
665300Sbill 	}
666300Sbill 	dhtimer();
667280Sbill }
6682395Swnj 
6692468Swnj /*
6702468Swnj  * At software clock interrupt time or after a UNIBUS reset
6712468Swnj  * empty all the dh silos.
6722468Swnj  */
6732456Swnj dhtimer()
6742456Swnj {
6752456Swnj 	register int dh;
6762456Swnj 
6772643Swnj 	for (dh = 0; dh < NDH; dh++)
6782456Swnj 		dhrint(dh);
6792456Swnj }
6802456Swnj 
6812468Swnj /*
6822479Swnj  * Turn on the line associated with dh dev.
6832468Swnj  */
6842468Swnj dmopen(dev)
6852468Swnj 	dev_t dev;
6862468Swnj {
6872468Swnj 	register struct tty *tp;
6882468Swnj 	register struct dmdevice *addr;
6892974Swnj 	register struct uba_device *ui;
6902468Swnj 	register int unit;
6912468Swnj 	register int dm;
6923792Swnj 	int s;
6932468Swnj 
6942468Swnj 	unit = minor(dev);
6952479Swnj 	dm = unit >> 4;
6962468Swnj 	tp = &dh11[unit];
6972566Swnj 	unit &= 0xf;
6982643Swnj 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
6992566Swnj 	    (dhsoftCAR[dm]&(1<<unit))) {
7005406Swnj 		tp->t_state |= TS_CARR_ON;
7012468Swnj 		return;
7022468Swnj 	}
7032468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7043792Swnj 	s = spl5();
7052479Swnj 	addr->dmcsr &= ~DM_SE;
7062479Swnj 	while (addr->dmcsr & DM_BUSY)
7072468Swnj 		;
7082566Swnj 	addr->dmcsr = unit;
7092479Swnj 	addr->dmlstat = DML_ON;
7102479Swnj 	if (addr->dmlstat&DML_CAR)
7115406Swnj 		tp->t_state |= TS_CARR_ON;
7123792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7135406Swnj 	while ((tp->t_state&TS_CARR_ON)==0)
7142468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
7153792Swnj 	splx(s);
7162468Swnj }
7172468Swnj 
7182468Swnj /*
7192468Swnj  * Dump control bits into the DM registers.
7202468Swnj  */
7212468Swnj dmctl(dev, bits, how)
7222468Swnj 	dev_t dev;
7232468Swnj 	int bits, how;
7242468Swnj {
7252974Swnj 	register struct uba_device *ui;
7262468Swnj 	register struct dmdevice *addr;
7272468Swnj 	register int unit, s;
7282468Swnj 	int dm;
7292468Swnj 
7302468Swnj 	unit = minor(dev);
7312468Swnj 	dm = unit >> 4;
7322468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7332468Swnj 		return;
7342468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7352468Swnj 	s = spl5();
7362479Swnj 	addr->dmcsr &= ~DM_SE;
7372479Swnj 	while (addr->dmcsr & DM_BUSY)
7382468Swnj 		;
7392468Swnj 	addr->dmcsr = unit & 0xf;
7402468Swnj 	switch(how) {
7412468Swnj 	case DMSET:
7422468Swnj 		addr->dmlstat = bits;
7432468Swnj 		break;
7442468Swnj 	case DMBIS:
7452468Swnj 		addr->dmlstat |= bits;
7462468Swnj 		break;
7472468Swnj 	case DMBIC:
7482468Swnj 		addr->dmlstat &= ~bits;
7492468Swnj 		break;
7502468Swnj 	}
7513792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7522468Swnj 	splx(s);
7532468Swnj }
7542468Swnj 
7552468Swnj /*
7562468Swnj  * DM11 interrupt; deal with carrier transitions.
7572468Swnj  */
7582468Swnj dmintr(dm)
7592468Swnj 	register int dm;
7602468Swnj {
7612974Swnj 	register struct uba_device *ui;
7622468Swnj 	register struct tty *tp;
7632468Swnj 	register struct dmdevice *addr;
7642468Swnj 
7652468Swnj 	ui = dminfo[dm];
7662479Swnj 	if (ui == 0)
7672479Swnj 		return;
7682468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7693997Sroot 	if (addr->dmcsr&DM_DONE) {
7703997Sroot 		if (addr->dmcsr&DM_CF) {
7713997Sroot 			tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
7723997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7735406Swnj 			if ((tp->t_state&TS_WOPEN)==0 &&
7743997Sroot 			    (tp->t_local&LMDMBUF)) {
7753997Sroot 				if (addr->dmlstat & DML_CAR) {
7765406Swnj 					tp->t_state &= ~TS_TTSTOP;
7773997Sroot 					ttstart(tp);
7785406Swnj 				} else if ((tp->t_state&TS_TTSTOP) == 0) {
7795406Swnj 					tp->t_state |= TS_TTSTOP;
7803997Sroot 					dhstop(tp, 0);
7813997Sroot 				}
7823997Sroot 			} else if ((addr->dmlstat&DML_CAR)==0) {
7835406Swnj 				if ((tp->t_state&TS_WOPEN)==0 &&
7843997Sroot 				    (tp->t_local&LNOHANG)==0) {
7853997Sroot 					gsignal(tp->t_pgrp, SIGHUP);
7863997Sroot 					gsignal(tp->t_pgrp, SIGCONT);
7873997Sroot 					addr->dmlstat = 0;
7883997Sroot 					flushtty(tp, FREAD|FWRITE);
7893997Sroot 				}
7905406Swnj 				tp->t_state &= ~TS_CARR_ON;
7913997Sroot 			} else
7925406Swnj 				tp->t_state |= TS_CARR_ON;
7933997Sroot 		}
7943997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7952468Swnj 	}
7962468Swnj }
7972625Swnj #endif
798