xref: /csrg-svn/sys/vax/uba/dh.c (revision 9771)
1*9771Ssam /*	dh.c	4.56	82/12/17	*/
213Sbill 
31934Swnj #include "dh.h"
42643Swnj #if NDH > 0
513Sbill /*
62479Swnj  * DH-11/DM-11 driver
713Sbill  */
8*9771Ssam #include "../machine/pte.h"
9*9771Ssam 
102730Swnj #include "bk.h"
1113Sbill #include "../h/param.h"
1213Sbill #include "../h/conf.h"
1313Sbill #include "../h/dir.h"
1413Sbill #include "../h/user.h"
156185Ssam #include "../h/proc.h"
169549Ssam #include "../h/ioctl.h"
1713Sbill #include "../h/tty.h"
1813Sbill #include "../h/map.h"
192395Swnj #include "../h/buf.h"
202566Swnj #include "../h/vm.h"
218472Sroot 
228472Sroot #include "../vaxuba/ubareg.h"
238472Sroot #include "../vaxuba/ubavar.h"
248472Sroot 
25113Sbill #include "../h/bk.h"
261561Sbill #include "../h/clist.h"
272468Swnj #include "../h/file.h"
287725Sroot #include "../h/uio.h"
2913Sbill 
302468Swnj /*
312479Swnj  * Definition of the driver for the auto-configuration program.
322479Swnj  * There is one definition for the dh and one for the dm.
332468Swnj  */
342605Swnj int	dhprobe(), dhattach(), dhrint(), dhxint();
352974Swnj struct	uba_device *dhinfo[NDH];
362395Swnj u_short	dhstd[] = { 0 };
372395Swnj struct	uba_driver dhdriver =
382605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
392395Swnj 
402605Swnj int	dmprobe(), dmattach(), dmintr();
412974Swnj struct	uba_device *dminfo[NDH];
422479Swnj u_short	dmstd[] = { 0 };
432479Swnj struct	uba_driver dmdriver =
442605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
4513Sbill 
462479Swnj struct dhdevice
472479Swnj {
482479Swnj 	union {
492479Swnj 		short	dhcsr;		/* control-status register */
502479Swnj 		char	dhcsrl;		/* low byte for line select */
512479Swnj 	} un;
522479Swnj 	short	dhrcr;			/* receive character register */
532479Swnj 	short	dhlpr;			/* line parameter register */
542479Swnj 	u_short dhcar;			/* current address register */
552479Swnj 	short	dhbcr;			/* byte count register */
562479Swnj 	u_short	dhbar;			/* buffer active register */
572479Swnj 	short	dhbreak;		/* break control register */
582479Swnj 	short	dhsilo;			/* silo status register */
592479Swnj };
6013Sbill 
616615Ssam #ifndef	PORTSELECTOR
626615Ssam #define	ISPEED	B300
636615Ssam #define	IFLAGS	(EVENP|ODDP|ECHO)
646615Ssam #else
656615Ssam #define	ISPEED	B4800
666615Ssam #define	IFLAGS	(EVENP|ODDP)
676615Ssam #endif
686615Ssam 
692456Swnj /* Bits in dhcsr */
702456Swnj #define	DH_TI	0100000		/* transmit interrupt */
712456Swnj #define	DH_SI	0040000		/* storage interrupt */
722456Swnj #define	DH_TIE	0020000		/* transmit interrupt enable */
732456Swnj #define	DH_SIE	0010000		/* storage interrupt enable */
742456Swnj #define	DH_MC	0004000		/* master clear */
752456Swnj #define	DH_NXM	0002000		/* non-existant memory */
762456Swnj #define	DH_MM	0001000		/* maintenance mode */
772456Swnj #define	DH_CNI	0000400		/* clear non-existant memory interrupt */
782456Swnj #define	DH_RI	0000200		/* receiver interrupt */
792456Swnj #define	DH_RIE	0000100		/* receiver interrupt enable */
8013Sbill 
812479Swnj /* Bits in dhlpr */
822479Swnj #define	BITS6	01
832479Swnj #define	BITS7	02
842479Swnj #define	BITS8	03
852479Swnj #define	TWOSB	04
862479Swnj #define	PENABLE	020
872479Swnj /* DEC manuals incorrectly say this bit causes generation of even parity. */
882479Swnj #define	OPAR	040
892479Swnj #define	HDUPLX	040000
902479Swnj 
912456Swnj #define	DH_IE	(DH_TIE|DH_SIE|DH_RIE)
922456Swnj 
932456Swnj /* Bits in dhrcr */
942479Swnj #define	DH_PE		0010000		/* parity error */
952479Swnj #define	DH_FE		0020000		/* framing error */
962479Swnj #define	DH_DO		0040000		/* data overrun */
972456Swnj 
982479Swnj struct dmdevice
992479Swnj {
1002479Swnj 	short	dmcsr;		/* control status register */
1012479Swnj 	short	dmlstat;	/* line status register */
1022479Swnj 	short	dmpad1[2];
1032479Swnj };
1042479Swnj 
1052479Swnj /* bits in dm csr */
1062479Swnj #define	DM_RF		0100000		/* ring flag */
1072479Swnj #define	DM_CF		0040000		/* carrier flag */
1082479Swnj #define	DM_CTS		0020000		/* clear to send */
1092479Swnj #define	DM_SRF		0010000		/* secondary receive flag */
1102479Swnj #define	DM_CS		0004000		/* clear scan */
1112479Swnj #define	DM_CM		0002000		/* clear multiplexor */
1122479Swnj #define	DM_MM		0001000		/* maintenance mode */
1132479Swnj #define	DM_STP		0000400		/* step */
1142479Swnj #define	DM_DONE		0000200		/* scanner is done */
1152479Swnj #define	DM_IE		0000100		/* interrupt enable */
1162479Swnj #define	DM_SE		0000040		/* scan enable */
1172479Swnj #define	DM_BUSY		0000020		/* scan busy */
1182479Swnj 
1192479Swnj /* bits in dm lsr */
1202479Swnj #define	DML_RNG		0000200		/* ring */
1212479Swnj #define	DML_CAR		0000100		/* carrier detect */
1222479Swnj #define	DML_CTS		0000040		/* clear to send */
1232479Swnj #define	DML_SR		0000020		/* secondary receive */
1242479Swnj #define	DML_ST		0000010		/* secondary transmit */
1252479Swnj #define	DML_RTS		0000004		/* request to send */
1262479Swnj #define	DML_DTR		0000002		/* data terminal ready */
1272479Swnj #define	DML_LE		0000001		/* line enable */
1282479Swnj 
1293792Swnj #define	DML_ON		(DML_DTR|DML_RTS|DML_LE)
1302479Swnj #define	DML_OFF		(DML_LE)
1312479Swnj 
13213Sbill /*
1332479Swnj  * Local variables for the driver
13413Sbill  */
1352643Swnj short	dhsar[NDH];			/* software copy of last bar */
1362643Swnj short	dhsoftCAR[NDH];
13713Sbill 
1382643Swnj struct	tty dh11[NDH*16];
1392643Swnj int	ndh11	= NDH*16;
1402479Swnj int	dhact;				/* mask of active dh's */
1412479Swnj int	dhstart(), ttrstrt();
14213Sbill 
1432479Swnj /*
1442479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
1452479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1462479Swnj  * into an i/o space address for the DMA routine.
1472479Swnj  */
1482479Swnj int	dh_ubinfo[MAXNUBA];		/* info about allocated unibus map */
1492479Swnj int	cbase[MAXNUBA];			/* base address in unibus map */
1502479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
15113Sbill 
1522456Swnj /*
1532456Swnj  * Routine for configuration to force a dh to interrupt.
1542456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1552456Swnj  */
1562468Swnj /*ARGSUSED*/
1572605Swnj dhprobe(reg)
1582395Swnj 	caddr_t reg;
1592395Swnj {
1602468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1612479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1622395Swnj 
1632605Swnj #ifdef lint
1642605Swnj 	br = 0; cvec = br; br = cvec;
1657384Sroot 	if (ndh11 == 0) ndh11 = 1;
1664932Swnj 	dhrint(0); dhxint(0);
1672605Swnj #endif
1682696Swnj #ifndef notdef
1692566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1706380Swnj 	DELAY(1000);
1717384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1722566Swnj 	dhaddr->un.dhcsr = 0;
1732566Swnj #else
1742456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1752456Swnj 	DELAY(5);
1762456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1772421Skre 	dhaddr->dhbcr = -1;
1782456Swnj 	dhaddr->dhcar = 0;
1792421Skre 	dhaddr->dhbar = 1;
1802456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1812421Skre 	dhaddr->un.dhcsr = 0;
1822456Swnj 	if (cvec && cvec != 0x200)
1832456Swnj 		cvec -= 4;		/* transmit -> receive */
1842482Swnj #endif
1857408Skre 	return (sizeof (struct dhdevice));
1862395Swnj }
1872395Swnj 
1882456Swnj /*
1892605Swnj  * Routine called to attach a dh.
1902456Swnj  */
1912605Swnj dhattach(ui)
1922974Swnj 	struct uba_device *ui;
1932395Swnj {
1942395Swnj 
1952566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1962395Swnj }
1972395Swnj 
19813Sbill /*
1992479Swnj  * Configuration routine to cause a dm to interrupt.
2002479Swnj  */
2012605Swnj dmprobe(reg)
2022605Swnj 	caddr_t reg;
2032479Swnj {
2042479Swnj 	register int br, vec;			/* value-result */
2052605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
2062479Swnj 
2072605Swnj #ifdef lint
2083101Swnj 	br = 0; vec = br; br = vec;
2096185Ssam 	dmintr(0);
2102605Swnj #endif
2112479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
2122479Swnj 	DELAY(20);
2132479Swnj 	dmaddr->dmcsr = 0;
2142605Swnj 	return (1);
2152479Swnj }
2162479Swnj 
2172605Swnj /*ARGSUSED*/
2182605Swnj dmattach(ui)
2192974Swnj 	struct uba_device *ui;
2202479Swnj {
2212479Swnj 
2222479Swnj 	/* no local state to set up */
2232479Swnj }
2242479Swnj 
2252479Swnj /*
2262468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
2272468Swnj  * is the first dh on this uba.  Turn on this dh if this is
2282468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
22913Sbill  */
23013Sbill /*ARGSUSED*/
23113Sbill dhopen(dev, flag)
2322395Swnj 	dev_t dev;
23313Sbill {
23413Sbill 	register struct tty *tp;
2352395Swnj 	register int unit, dh;
2362479Swnj 	register struct dhdevice *addr;
2372974Swnj 	register struct uba_device *ui;
23813Sbill 	int s;
23913Sbill 
2402395Swnj 	unit = minor(dev);
2412395Swnj 	dh = unit >> 4;
2428566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
2438566Sroot 		return (ENXIO);
2442395Swnj 	tp = &dh11[unit];
2458566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
2468566Sroot 		return (EBUSY);
2472479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
24813Sbill 	tp->t_addr = (caddr_t)addr;
24913Sbill 	tp->t_oproc = dhstart;
2505406Swnj 	tp->t_state |= TS_WOPEN;
2512468Swnj 	/*
2522468Swnj 	 * While setting up state for this uba and this dh,
2532468Swnj 	 * block uba resets which can clear the state.
2542468Swnj 	 */
2552468Swnj 	s = spl5();
2562421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
257717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
2582395Swnj 		dh_ubinfo[ui->ui_ubanum] =
2592421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2602770Swnj 			512+nclist*sizeof(struct cblock), 0);
2612456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
26213Sbill 	}
2632456Swnj 	if ((dhact&(1<<dh)) == 0) {
2642456Swnj 		addr->un.dhcsr |= DH_IE;
2652468Swnj 		dhact |= (1<<dh);
2662456Swnj 		addr->dhsilo = 16;
2672456Swnj 	}
26813Sbill 	splx(s);
2692468Swnj 	/*
2702468Swnj 	 * If this is first open, initialze tty state to default.
2712468Swnj 	 */
2725406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
27313Sbill 		ttychars(tp);
2746615Ssam #ifndef PORTSELECTOR
275168Sbill 		if (tp->t_ispeed == 0) {
2766615Ssam #endif
2776615Ssam 			tp->t_ispeed = ISPEED;
2786615Ssam 			tp->t_ospeed = ISPEED;
2796615Ssam 			tp->t_flags = IFLAGS;
2806615Ssam #ifndef PORTSELECTOR
281168Sbill 		}
2826615Ssam #endif
2832395Swnj 		dhparam(unit);
28413Sbill 	}
2852468Swnj 	/*
2862468Swnj 	 * Wait for carrier, then process line discipline specific open.
2872468Swnj 	 */
28813Sbill 	dmopen(dev);
2898566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
29013Sbill }
29113Sbill 
29213Sbill /*
2932468Swnj  * Close a DH11 line, turning off the DM11.
29413Sbill  */
29513Sbill /*ARGSUSED*/
29613Sbill dhclose(dev, flag)
2972395Swnj 	dev_t dev;
2982395Swnj 	int flag;
29913Sbill {
30013Sbill 	register struct tty *tp;
3012395Swnj 	register unit;
30213Sbill 
3032395Swnj 	unit = minor(dev);
3042395Swnj 	tp = &dh11[unit];
30513Sbill 	(*linesw[tp->t_line].l_close)(tp);
3062479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
3075406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
3082479Swnj 		dmctl(unit, DML_OFF, DMSET);
30913Sbill 	ttyclose(tp);
31013Sbill }
31113Sbill 
3127725Sroot dhread(dev, uio)
3132395Swnj 	dev_t dev;
3147725Sroot 	struct uio *uio;
31513Sbill {
3168490Sroot 	register struct tty *tp = &dh11[minor(dev)];
31713Sbill 
3187725Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
31913Sbill }
32013Sbill 
3217831Sroot dhwrite(dev, uio)
3222395Swnj 	dev_t dev;
3237831Sroot 	struct uio *uio;
32413Sbill {
3258490Sroot 	register struct tty *tp = &dh11[minor(dev)];
32613Sbill 
3278490Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
32813Sbill }
32913Sbill 
33013Sbill /*
33113Sbill  * DH11 receiver interrupt.
33213Sbill  */
3332395Swnj dhrint(dh)
3342395Swnj 	int dh;
33513Sbill {
33613Sbill 	register struct tty *tp;
3372395Swnj 	register c;
3382479Swnj 	register struct dhdevice *addr;
339117Sbill 	register struct tty *tp0;
3402974Swnj 	register struct uba_device *ui;
3412924Swnj 	int overrun = 0;
34213Sbill 
3432395Swnj 	ui = dhinfo[dh];
3442479Swnj 	if (ui == 0 || ui->ui_alive == 0)
3452479Swnj 		return;
3462479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3472468Swnj 	tp0 = &dh11[dh<<4];
3482468Swnj 	/*
3492468Swnj 	 * Loop fetching characters from the silo for this
3502468Swnj 	 * dh until there are no more in the silo.
3512468Swnj 	 */
3522468Swnj 	while ((c = addr->dhrcr) < 0) {
3532468Swnj 		tp = tp0 + ((c>>8)&0xf);
3546615Ssam #ifndef PORTSELECTOR
3555406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
3566615Ssam #else
3576615Ssam 		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
3586615Ssam #endif
35913Sbill 			wakeup((caddr_t)tp);
36013Sbill 			continue;
36113Sbill 		}
3622468Swnj 		if (c & DH_PE)
36313Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
36413Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
36513Sbill 				continue;
3662924Swnj 		if ((c & DH_DO) && overrun == 0) {
3672924Swnj 			printf("dh%d: silo overflow\n", dh);
3682924Swnj 			overrun = 1;
3692924Swnj 		}
3702468Swnj 		if (c & DH_FE)
3712468Swnj 			/*
3722468Swnj 			 * At framing error (break) generate
3732468Swnj 			 * a null (in raw mode, for getty), or a
3742468Swnj 			 * interrupt (in cooked/cbreak mode).
3752468Swnj 			 */
37613Sbill 			if (tp->t_flags&RAW)
3772468Swnj 				c = 0;
37813Sbill 			else
3799549Ssam 				c = tp->t_intrc;
3802730Swnj #if NBK > 0
381139Sbill 		if (tp->t_line == NETLDISC) {
382117Sbill 			c &= 0177;
383168Sbill 			BKINPUT(c, tp);
384117Sbill 		} else
3852730Swnj #endif
3862468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
38713Sbill 	}
38813Sbill }
38913Sbill 
39013Sbill /*
3912468Swnj  * Ioctl for DH11.
39213Sbill  */
39313Sbill /*ARGSUSED*/
3947629Ssam dhioctl(dev, cmd, data, flag)
3957629Ssam 	caddr_t data;
39613Sbill {
39713Sbill 	register struct tty *tp;
3988566Sroot 	register int unit = minor(dev);
3998566Sroot 	int error;
40013Sbill 
4012395Swnj 	tp = &dh11[unit];
4028566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
4038566Sroot 	if (error >= 0)
4048566Sroot 		return (error);
4058566Sroot 	error = ttioctl(tp, cmd, data, flag);
4068566Sroot 	if (error >= 0) {
4077629Ssam 		if (cmd == TIOCSETP || cmd == TIOCSETN)
4082395Swnj 			dhparam(unit);
4098566Sroot 		return (error);
4108566Sroot 	}
4118566Sroot 	switch (cmd) {
4127629Ssam 
413168Sbill 	case TIOCSBRK:
4142479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
415168Sbill 		break;
4167629Ssam 
417168Sbill 	case TIOCCBRK:
4182479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
419168Sbill 		break;
4207629Ssam 
421168Sbill 	case TIOCSDTR:
4222479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
423168Sbill 		break;
4247629Ssam 
425168Sbill 	case TIOCCDTR:
4262479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
427168Sbill 		break;
4287629Ssam 
429168Sbill 	default:
4308566Sroot 		return (ENOTTY);
431168Sbill 	}
4328566Sroot 	return (0);
43313Sbill }
43413Sbill 
43513Sbill /*
43613Sbill  * Set parameters from open or stty into the DH hardware
43713Sbill  * registers.
43813Sbill  */
4392395Swnj dhparam(unit)
4402395Swnj 	register int unit;
44113Sbill {
44213Sbill 	register struct tty *tp;
4432479Swnj 	register struct dhdevice *addr;
4442395Swnj 	register int lpar;
445300Sbill 	int s;
44613Sbill 
4472395Swnj 	tp = &dh11[unit];
4482479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4492468Swnj 	/*
4502468Swnj 	 * Block interrupts so parameters will be set
4512468Swnj 	 * before the line interrupts.
4522468Swnj 	 */
453300Sbill 	s = spl5();
4542468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
45513Sbill 	if ((tp->t_ispeed)==0) {
4565406Swnj 		tp->t_state |= TS_HUPCLS;
4572479Swnj 		dmctl(unit, DML_OFF, DMSET);
45813Sbill 		return;
45913Sbill 	}
4602395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4612468Swnj 	if ((tp->t_ispeed) == B134)
4622395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4639549Ssam 	else if (tp->t_flags & (RAW|LITOUT))
4642395Swnj 		lpar |= BITS8;
46513Sbill 	else
4662395Swnj 		lpar |= BITS7|PENABLE;
46713Sbill 	if ((tp->t_flags&EVENP) == 0)
4682395Swnj 		lpar |= OPAR;
4692468Swnj 	if ((tp->t_ospeed) == B110)
4702395Swnj 		lpar |= TWOSB;
4712395Swnj 	addr->dhlpr = lpar;
472300Sbill 	splx(s);
47313Sbill }
47413Sbill 
47513Sbill /*
47613Sbill  * DH11 transmitter interrupt.
47713Sbill  * Restart each line which used to be active but has
47813Sbill  * terminated transmission since the last interrupt.
47913Sbill  */
4802395Swnj dhxint(dh)
4812395Swnj 	int dh;
48213Sbill {
48313Sbill 	register struct tty *tp;
4842479Swnj 	register struct dhdevice *addr;
48513Sbill 	short ttybit, bar, *sbar;
4862974Swnj 	register struct uba_device *ui;
4872468Swnj 	register int unit;
4882605Swnj 	u_short cntr;
48913Sbill 
4902395Swnj 	ui = dhinfo[dh];
4912479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4922456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4932456Swnj 		addr->un.dhcsr |= DH_CNI;
4942924Swnj 		printf("dh%d: NXM\n", dh);
495105Sbill 	}
4962395Swnj 	sbar = &dhsar[dh];
49713Sbill 	bar = *sbar & ~addr->dhbar;
4982395Swnj 	unit = dh * 16; ttybit = 1;
4992468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
5002468Swnj 	for (; bar; unit++, ttybit <<= 1) {
5012468Swnj 		if (bar & ttybit) {
50213Sbill 			*sbar &= ~ttybit;
50313Sbill 			bar &= ~ttybit;
5042395Swnj 			tp = &dh11[unit];
5055406Swnj 			tp->t_state &= ~TS_BUSY;
5065406Swnj 			if (tp->t_state&TS_FLUSH)
5075406Swnj 				tp->t_state &= ~TS_FLUSH;
508113Sbill 			else {
5092456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
5102468Swnj 				/*
5112468Swnj 				 * Do arithmetic in a short to make up
5122468Swnj 				 * for lost 16&17 bits.
5132468Swnj 				 */
5142605Swnj 				cntr = addr->dhcar -
5152468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
5163101Swnj 				ndflush(&tp->t_outq, (int)cntr);
517113Sbill 			}
518113Sbill 			if (tp->t_line)
51913Sbill 				(*linesw[tp->t_line].l_start)(tp);
520113Sbill 			else
52113Sbill 				dhstart(tp);
52213Sbill 		}
52313Sbill 	}
52413Sbill }
52513Sbill 
52613Sbill /*
52713Sbill  * Start (restart) transmission on the given DH11 line.
52813Sbill  */
52913Sbill dhstart(tp)
5302395Swnj 	register struct tty *tp;
53113Sbill {
5322479Swnj 	register struct dhdevice *addr;
5332468Swnj 	register int car, dh, unit, nch;
5342395Swnj 	int s;
53513Sbill 
5362468Swnj 	unit = minor(tp->t_dev);
5372468Swnj 	dh = unit >> 4;
5382468Swnj 	unit &= 0xf;
5392479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5402468Swnj 
54113Sbill 	/*
5422468Swnj 	 * Must hold interrupts in following code to prevent
5432468Swnj 	 * state of the tp from changing.
54413Sbill 	 */
54513Sbill 	s = spl5();
5462468Swnj 	/*
5472468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5482468Swnj 	 */
5495406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
55013Sbill 		goto out;
5512468Swnj 	/*
5522468Swnj 	 * If there are sleepers, and output has drained below low
5532468Swnj 	 * water mark, wake up the sleepers.
5542468Swnj 	 */
5555406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
5565406Swnj 		if (tp->t_state&TS_ASLEEP) {
5575406Swnj 			tp->t_state &= ~TS_ASLEEP;
5585406Swnj 			wakeup((caddr_t)&tp->t_outq);
5595406Swnj 		}
5605406Swnj 		if (tp->t_wsel) {
5615406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5625406Swnj 			tp->t_wsel = 0;
5635406Swnj 			tp->t_state &= ~TS_WCOLL;
5645406Swnj 		}
56513Sbill 	}
5662468Swnj 	/*
5672468Swnj 	 * Now restart transmission unless the output queue is
5682468Swnj 	 * empty.
5692468Swnj 	 */
57013Sbill 	if (tp->t_outq.c_cc == 0)
57113Sbill 		goto out;
5729549Ssam 	if (tp->t_flags & (RAW|LITOUT))
57313Sbill 		nch = ndqb(&tp->t_outq, 0);
5742395Swnj 	else {
57513Sbill 		nch = ndqb(&tp->t_outq, 0200);
5762468Swnj 		/*
5772468Swnj 		 * If first thing on queue is a delay process it.
5782468Swnj 		 */
57913Sbill 		if (nch == 0) {
58013Sbill 			nch = getc(&tp->t_outq);
5812468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5825406Swnj 			tp->t_state |= TS_TIMEOUT;
58313Sbill 			goto out;
58413Sbill 		}
58513Sbill 	}
5862468Swnj 	/*
5872468Swnj 	 * If characters to transmit, restart transmission.
5882468Swnj 	 */
58913Sbill 	if (nch) {
5902468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5912468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5923586Sroot 		/*
5933586Sroot 		 * The following nonsense with short word
5943586Sroot 		 * is to make sure the dhbar |= word below
5953586Sroot 		 * is done with an interlocking bisw2 instruction.
5963586Sroot 		 */
5973586Sroot 		{ short word = 1 << unit;
5983586Sroot 		dhsar[dh] |= word;
5992468Swnj 		addr->dhcar = car;
60013Sbill 		addr->dhbcr = -nch;
6013586Sroot 		addr->dhbar |= word;
6023586Sroot 		}
6035406Swnj 		tp->t_state |= TS_BUSY;
60413Sbill 	}
6052395Swnj out:
60613Sbill 	splx(s);
60713Sbill }
60813Sbill 
60913Sbill /*
6102468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
61113Sbill  */
61213Sbill /*ARGSUSED*/
61313Sbill dhstop(tp, flag)
6142468Swnj 	register struct tty *tp;
61513Sbill {
6162479Swnj 	register struct dhdevice *addr;
6172395Swnj 	register int unit, s;
61813Sbill 
6192479Swnj 	addr = (struct dhdevice *)tp->t_addr;
6202468Swnj 	/*
6212468Swnj 	 * Block input/output interrupts while messing with state.
6222468Swnj 	 */
6232468Swnj 	s = spl5();
6245406Swnj 	if (tp->t_state & TS_BUSY) {
6252468Swnj 		/*
6262468Swnj 		 * Device is transmitting; stop output
6272468Swnj 		 * by selecting the line and setting the byte
6282468Swnj 		 * count to -1.  We will clean up later
6292468Swnj 		 * by examining the address where the dh stopped.
6302468Swnj 		 */
6312395Swnj 		unit = minor(tp->t_dev);
6322456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
6335406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
6345406Swnj 			tp->t_state |= TS_FLUSH;
635113Sbill 		addr->dhbcr = -1;
636113Sbill 	}
63713Sbill 	splx(s);
63813Sbill }
63913Sbill 
640168Sbill /*
641280Sbill  * Reset state of driver if UBA reset was necessary.
642280Sbill  * Reset the csrl and lpr registers on open lines, and
643280Sbill  * restart transmitters.
644280Sbill  */
6452395Swnj dhreset(uban)
6462468Swnj 	int uban;
647280Sbill {
6482395Swnj 	register int dh, unit;
649280Sbill 	register struct tty *tp;
6502974Swnj 	register struct uba_device *ui;
6512421Skre 	int i;
652280Sbill 
6532421Skre 	if (dh_ubinfo[uban] == 0)
6542421Skre 		return;
6552421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6562770Swnj 	    512+nclist*sizeof (struct cblock), 0);
6572421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
6582395Swnj 	dh = 0;
6592643Swnj 	for (dh = 0; dh < NDH; dh++) {
6602421Skre 		ui = dhinfo[dh];
6612421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6622421Skre 			continue;
6632924Swnj 		printf(" dh%d", dh);
6642479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
6652479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
6662421Skre 		unit = dh * 16;
6672421Skre 		for (i = 0; i < 16; i++) {
6682421Skre 			tp = &dh11[unit];
6695406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6702421Skre 				dhparam(unit);
6712479Swnj 				dmctl(unit, DML_ON, DMSET);
6725406Swnj 				tp->t_state &= ~TS_BUSY;
6732421Skre 				dhstart(tp);
6742421Skre 			}
6752421Skre 			unit++;
676300Sbill 		}
677300Sbill 	}
678300Sbill 	dhtimer();
679280Sbill }
6802395Swnj 
6812468Swnj /*
6822468Swnj  * At software clock interrupt time or after a UNIBUS reset
6832468Swnj  * empty all the dh silos.
6842468Swnj  */
6852456Swnj dhtimer()
6862456Swnj {
6872456Swnj 	register int dh;
6888159Sroot 	register int s = spl5();
6892456Swnj 
6902643Swnj 	for (dh = 0; dh < NDH; dh++)
6912456Swnj 		dhrint(dh);
6928159Sroot 	splx(s);
6932456Swnj }
6942456Swnj 
6952468Swnj /*
6962479Swnj  * Turn on the line associated with dh dev.
6972468Swnj  */
6982468Swnj dmopen(dev)
6992468Swnj 	dev_t dev;
7002468Swnj {
7012468Swnj 	register struct tty *tp;
7022468Swnj 	register struct dmdevice *addr;
7032974Swnj 	register struct uba_device *ui;
7042468Swnj 	register int unit;
7052468Swnj 	register int dm;
7063792Swnj 	int s;
7072468Swnj 
7082468Swnj 	unit = minor(dev);
7092479Swnj 	dm = unit >> 4;
7102468Swnj 	tp = &dh11[unit];
7112566Swnj 	unit &= 0xf;
7122643Swnj 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
7132566Swnj 	    (dhsoftCAR[dm]&(1<<unit))) {
7145406Swnj 		tp->t_state |= TS_CARR_ON;
7152468Swnj 		return;
7162468Swnj 	}
7172468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7183792Swnj 	s = spl5();
7192479Swnj 	addr->dmcsr &= ~DM_SE;
7202479Swnj 	while (addr->dmcsr & DM_BUSY)
7212468Swnj 		;
7222566Swnj 	addr->dmcsr = unit;
7232479Swnj 	addr->dmlstat = DML_ON;
7242479Swnj 	if (addr->dmlstat&DML_CAR)
7255406Swnj 		tp->t_state |= TS_CARR_ON;
7263792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7275406Swnj 	while ((tp->t_state&TS_CARR_ON)==0)
7282468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
7293792Swnj 	splx(s);
7302468Swnj }
7312468Swnj 
7322468Swnj /*
7332468Swnj  * Dump control bits into the DM registers.
7342468Swnj  */
7352468Swnj dmctl(dev, bits, how)
7362468Swnj 	dev_t dev;
7372468Swnj 	int bits, how;
7382468Swnj {
7392974Swnj 	register struct uba_device *ui;
7402468Swnj 	register struct dmdevice *addr;
7412468Swnj 	register int unit, s;
7422468Swnj 	int dm;
7432468Swnj 
7442468Swnj 	unit = minor(dev);
7452468Swnj 	dm = unit >> 4;
7462468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7472468Swnj 		return;
7482468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7492468Swnj 	s = spl5();
7502479Swnj 	addr->dmcsr &= ~DM_SE;
7512479Swnj 	while (addr->dmcsr & DM_BUSY)
7522468Swnj 		;
7532468Swnj 	addr->dmcsr = unit & 0xf;
7542468Swnj 	switch(how) {
7552468Swnj 	case DMSET:
7562468Swnj 		addr->dmlstat = bits;
7572468Swnj 		break;
7582468Swnj 	case DMBIS:
7592468Swnj 		addr->dmlstat |= bits;
7602468Swnj 		break;
7612468Swnj 	case DMBIC:
7622468Swnj 		addr->dmlstat &= ~bits;
7632468Swnj 		break;
7642468Swnj 	}
7653792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7662468Swnj 	splx(s);
7672468Swnj }
7682468Swnj 
7692468Swnj /*
7702468Swnj  * DM11 interrupt; deal with carrier transitions.
7712468Swnj  */
7722468Swnj dmintr(dm)
7732468Swnj 	register int dm;
7742468Swnj {
7752974Swnj 	register struct uba_device *ui;
7762468Swnj 	register struct tty *tp;
7772468Swnj 	register struct dmdevice *addr;
7782468Swnj 
7792468Swnj 	ui = dminfo[dm];
7802479Swnj 	if (ui == 0)
7812479Swnj 		return;
7822468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7833997Sroot 	if (addr->dmcsr&DM_DONE) {
7843997Sroot 		if (addr->dmcsr&DM_CF) {
7853997Sroot 			tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
7863997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7879549Ssam 			if ((tp->t_state&TS_WOPEN) == 0 &&
7889605Ssam 			    (tp->t_flags & MDMBUF)) {
7893997Sroot 				if (addr->dmlstat & DML_CAR) {
7905406Swnj 					tp->t_state &= ~TS_TTSTOP;
7913997Sroot 					ttstart(tp);
7925406Swnj 				} else if ((tp->t_state&TS_TTSTOP) == 0) {
7935406Swnj 					tp->t_state |= TS_TTSTOP;
7943997Sroot 					dhstop(tp, 0);
7953997Sroot 				}
7963997Sroot 			} else if ((addr->dmlstat&DML_CAR)==0) {
7975406Swnj 				if ((tp->t_state&TS_WOPEN)==0 &&
7989605Ssam 				    (tp->t_flags & NOHANG) == 0) {
7993997Sroot 					gsignal(tp->t_pgrp, SIGHUP);
8003997Sroot 					gsignal(tp->t_pgrp, SIGCONT);
8013997Sroot 					addr->dmlstat = 0;
8023997Sroot 					flushtty(tp, FREAD|FWRITE);
8033997Sroot 				}
8045406Swnj 				tp->t_state &= ~TS_CARR_ON;
8053997Sroot 			} else
8065406Swnj 				tp->t_state |= TS_CARR_ON;
8073997Sroot 		}
8083997Sroot 		addr->dmcsr = DM_IE|DM_SE;
8092468Swnj 	}
8102468Swnj }
8112625Swnj #endif
812