xref: /csrg-svn/sys/vax/uba/dh.c (revision 16062)
1*16062Skarels /*	dh.c	6.2	84/02/16	*/
213Sbill 
31934Swnj #include "dh.h"
42643Swnj #if NDH > 0
513Sbill /*
62479Swnj  * DH-11/DM-11 driver
713Sbill  */
89771Ssam #include "../machine/pte.h"
99771Ssam 
102730Swnj #include "bk.h"
11*16062Skarels #include "uba.h"
1213Sbill #include "../h/param.h"
1313Sbill #include "../h/conf.h"
1413Sbill #include "../h/dir.h"
1513Sbill #include "../h/user.h"
166185Ssam #include "../h/proc.h"
179549Ssam #include "../h/ioctl.h"
1813Sbill #include "../h/tty.h"
1913Sbill #include "../h/map.h"
202395Swnj #include "../h/buf.h"
212566Swnj #include "../h/vm.h"
228472Sroot 
238472Sroot #include "../vaxuba/ubareg.h"
248472Sroot #include "../vaxuba/ubavar.h"
2510018Ssam #include "../vaxuba/dhreg.h"
2610018Ssam #include "../vaxuba/dmreg.h"
278472Sroot 
28113Sbill #include "../h/bk.h"
291561Sbill #include "../h/clist.h"
302468Swnj #include "../h/file.h"
317725Sroot #include "../h/uio.h"
3213Sbill 
332468Swnj /*
342479Swnj  * Definition of the driver for the auto-configuration program.
352479Swnj  * There is one definition for the dh and one for the dm.
362468Swnj  */
372605Swnj int	dhprobe(), dhattach(), dhrint(), dhxint();
382974Swnj struct	uba_device *dhinfo[NDH];
392395Swnj u_short	dhstd[] = { 0 };
402395Swnj struct	uba_driver dhdriver =
412605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
422395Swnj 
432605Swnj int	dmprobe(), dmattach(), dmintr();
442974Swnj struct	uba_device *dminfo[NDH];
452479Swnj u_short	dmstd[] = { 0 };
462479Swnj struct	uba_driver dmdriver =
472605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
4813Sbill 
496615Ssam #ifndef	PORTSELECTOR
506615Ssam #define	ISPEED	B300
516615Ssam #define	IFLAGS	(EVENP|ODDP|ECHO)
526615Ssam #else
536615Ssam #define	ISPEED	B4800
546615Ssam #define	IFLAGS	(EVENP|ODDP)
556615Ssam #endif
566615Ssam 
5713Sbill /*
582479Swnj  * Local variables for the driver
5913Sbill  */
602643Swnj short	dhsar[NDH];			/* software copy of last bar */
612643Swnj short	dhsoftCAR[NDH];
6213Sbill 
632643Swnj struct	tty dh11[NDH*16];
642643Swnj int	ndh11	= NDH*16;
652479Swnj int	dhact;				/* mask of active dh's */
662479Swnj int	dhstart(), ttrstrt();
6713Sbill 
682479Swnj /*
692479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
702479Swnj  * The UBACVT macro converts a clist space address for unibus uban
712479Swnj  * into an i/o space address for the DMA routine.
722479Swnj  */
73*16062Skarels int	dh_ubinfo[NUBA];		/* info about allocated unibus map */
74*16062Skarels int	cbase[NUBA];			/* base address in unibus map */
752479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
7613Sbill 
772456Swnj /*
782456Swnj  * Routine for configuration to force a dh to interrupt.
792456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
802456Swnj  */
812468Swnj /*ARGSUSED*/
822605Swnj dhprobe(reg)
832395Swnj 	caddr_t reg;
842395Swnj {
852468Swnj 	register int br, cvec;		/* these are ``value-result'' */
862479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
872395Swnj 
882605Swnj #ifdef lint
892605Swnj 	br = 0; cvec = br; br = cvec;
907384Sroot 	if (ndh11 == 0) ndh11 = 1;
914932Swnj 	dhrint(0); dhxint(0);
922605Swnj #endif
932696Swnj #ifndef notdef
942566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
956380Swnj 	DELAY(1000);
967384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
972566Swnj 	dhaddr->un.dhcsr = 0;
982566Swnj #else
992456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1002456Swnj 	DELAY(5);
1012456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1022421Skre 	dhaddr->dhbcr = -1;
1032456Swnj 	dhaddr->dhcar = 0;
1042421Skre 	dhaddr->dhbar = 1;
1052456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1062421Skre 	dhaddr->un.dhcsr = 0;
1072456Swnj 	if (cvec && cvec != 0x200)
1082456Swnj 		cvec -= 4;		/* transmit -> receive */
1092482Swnj #endif
1107408Skre 	return (sizeof (struct dhdevice));
1112395Swnj }
1122395Swnj 
1132456Swnj /*
1142605Swnj  * Routine called to attach a dh.
1152456Swnj  */
1162605Swnj dhattach(ui)
1172974Swnj 	struct uba_device *ui;
1182395Swnj {
1192395Swnj 
1202566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1212395Swnj }
1222395Swnj 
12313Sbill /*
1242479Swnj  * Configuration routine to cause a dm to interrupt.
1252479Swnj  */
1262605Swnj dmprobe(reg)
1272605Swnj 	caddr_t reg;
1282479Swnj {
1292479Swnj 	register int br, vec;			/* value-result */
1302605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1312479Swnj 
1322605Swnj #ifdef lint
1333101Swnj 	br = 0; vec = br; br = vec;
1346185Ssam 	dmintr(0);
1352605Swnj #endif
1362479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1372479Swnj 	DELAY(20);
1382479Swnj 	dmaddr->dmcsr = 0;
1392605Swnj 	return (1);
1402479Swnj }
1412479Swnj 
1422605Swnj /*ARGSUSED*/
1432605Swnj dmattach(ui)
1442974Swnj 	struct uba_device *ui;
1452479Swnj {
1462479Swnj 
1472479Swnj 	/* no local state to set up */
1482479Swnj }
1492479Swnj 
1502479Swnj /*
1512468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1522468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1532468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
15413Sbill  */
15513Sbill /*ARGSUSED*/
15613Sbill dhopen(dev, flag)
1572395Swnj 	dev_t dev;
15813Sbill {
15913Sbill 	register struct tty *tp;
1602395Swnj 	register int unit, dh;
1612479Swnj 	register struct dhdevice *addr;
1622974Swnj 	register struct uba_device *ui;
16313Sbill 	int s;
16413Sbill 
1652395Swnj 	unit = minor(dev);
1662395Swnj 	dh = unit >> 4;
1678566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
1688566Sroot 		return (ENXIO);
1692395Swnj 	tp = &dh11[unit];
1708566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
1718566Sroot 		return (EBUSY);
1722479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
17313Sbill 	tp->t_addr = (caddr_t)addr;
17413Sbill 	tp->t_oproc = dhstart;
1755406Swnj 	tp->t_state |= TS_WOPEN;
1762468Swnj 	/*
1772468Swnj 	 * While setting up state for this uba and this dh,
1782468Swnj 	 * block uba resets which can clear the state.
1792468Swnj 	 */
1802468Swnj 	s = spl5();
1812421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
182717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
1832395Swnj 		dh_ubinfo[ui->ui_ubanum] =
1842421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
1852770Swnj 			512+nclist*sizeof(struct cblock), 0);
1862456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
18713Sbill 	}
1882456Swnj 	if ((dhact&(1<<dh)) == 0) {
1892456Swnj 		addr->un.dhcsr |= DH_IE;
1902468Swnj 		dhact |= (1<<dh);
1912456Swnj 		addr->dhsilo = 16;
1922456Swnj 	}
19313Sbill 	splx(s);
1942468Swnj 	/*
1952468Swnj 	 * If this is first open, initialze tty state to default.
1962468Swnj 	 */
1975406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
19813Sbill 		ttychars(tp);
1996615Ssam #ifndef PORTSELECTOR
200168Sbill 		if (tp->t_ispeed == 0) {
2016615Ssam #endif
2026615Ssam 			tp->t_ispeed = ISPEED;
2036615Ssam 			tp->t_ospeed = ISPEED;
2046615Ssam 			tp->t_flags = IFLAGS;
2056615Ssam #ifndef PORTSELECTOR
206168Sbill 		}
2076615Ssam #endif
2082395Swnj 		dhparam(unit);
20913Sbill 	}
2102468Swnj 	/*
2112468Swnj 	 * Wait for carrier, then process line discipline specific open.
2122468Swnj 	 */
21313Sbill 	dmopen(dev);
2148566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
21513Sbill }
21613Sbill 
21713Sbill /*
2182468Swnj  * Close a DH11 line, turning off the DM11.
21913Sbill  */
22013Sbill /*ARGSUSED*/
22113Sbill dhclose(dev, flag)
2222395Swnj 	dev_t dev;
2232395Swnj 	int flag;
22413Sbill {
22513Sbill 	register struct tty *tp;
2262395Swnj 	register unit;
22713Sbill 
2282395Swnj 	unit = minor(dev);
2292395Swnj 	tp = &dh11[unit];
23013Sbill 	(*linesw[tp->t_line].l_close)(tp);
2312479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
2325406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
2332479Swnj 		dmctl(unit, DML_OFF, DMSET);
23413Sbill 	ttyclose(tp);
23513Sbill }
23613Sbill 
2377725Sroot dhread(dev, uio)
2382395Swnj 	dev_t dev;
2397725Sroot 	struct uio *uio;
24013Sbill {
2418490Sroot 	register struct tty *tp = &dh11[minor(dev)];
24213Sbill 
2437725Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
24413Sbill }
24513Sbill 
2467831Sroot dhwrite(dev, uio)
2472395Swnj 	dev_t dev;
2487831Sroot 	struct uio *uio;
24913Sbill {
2508490Sroot 	register struct tty *tp = &dh11[minor(dev)];
25113Sbill 
2528490Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
25313Sbill }
25413Sbill 
25513Sbill /*
25613Sbill  * DH11 receiver interrupt.
25713Sbill  */
2582395Swnj dhrint(dh)
2592395Swnj 	int dh;
26013Sbill {
26113Sbill 	register struct tty *tp;
2622395Swnj 	register c;
2632479Swnj 	register struct dhdevice *addr;
264117Sbill 	register struct tty *tp0;
2652974Swnj 	register struct uba_device *ui;
2662924Swnj 	int overrun = 0;
26713Sbill 
2682395Swnj 	ui = dhinfo[dh];
2692479Swnj 	if (ui == 0 || ui->ui_alive == 0)
2702479Swnj 		return;
2712479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
2722468Swnj 	tp0 = &dh11[dh<<4];
2732468Swnj 	/*
2742468Swnj 	 * Loop fetching characters from the silo for this
2752468Swnj 	 * dh until there are no more in the silo.
2762468Swnj 	 */
2772468Swnj 	while ((c = addr->dhrcr) < 0) {
2782468Swnj 		tp = tp0 + ((c>>8)&0xf);
2796615Ssam #ifndef PORTSELECTOR
2805406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
2816615Ssam #else
2826615Ssam 		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
2836615Ssam #endif
28413Sbill 			wakeup((caddr_t)tp);
28513Sbill 			continue;
28613Sbill 		}
2872468Swnj 		if (c & DH_PE)
28813Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
28913Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
29013Sbill 				continue;
2912924Swnj 		if ((c & DH_DO) && overrun == 0) {
2922924Swnj 			printf("dh%d: silo overflow\n", dh);
2932924Swnj 			overrun = 1;
2942924Swnj 		}
2952468Swnj 		if (c & DH_FE)
2962468Swnj 			/*
2972468Swnj 			 * At framing error (break) generate
2982468Swnj 			 * a null (in raw mode, for getty), or a
2992468Swnj 			 * interrupt (in cooked/cbreak mode).
3002468Swnj 			 */
30113Sbill 			if (tp->t_flags&RAW)
3022468Swnj 				c = 0;
30313Sbill 			else
3049549Ssam 				c = tp->t_intrc;
3052730Swnj #if NBK > 0
306139Sbill 		if (tp->t_line == NETLDISC) {
307117Sbill 			c &= 0177;
308168Sbill 			BKINPUT(c, tp);
309117Sbill 		} else
3102730Swnj #endif
3112468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
31213Sbill 	}
31313Sbill }
31413Sbill 
31513Sbill /*
3162468Swnj  * Ioctl for DH11.
31713Sbill  */
31813Sbill /*ARGSUSED*/
3197629Ssam dhioctl(dev, cmd, data, flag)
3207629Ssam 	caddr_t data;
32113Sbill {
32213Sbill 	register struct tty *tp;
3238566Sroot 	register int unit = minor(dev);
3248566Sroot 	int error;
32513Sbill 
3262395Swnj 	tp = &dh11[unit];
3278566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3288566Sroot 	if (error >= 0)
3298566Sroot 		return (error);
3308566Sroot 	error = ttioctl(tp, cmd, data, flag);
3318566Sroot 	if (error >= 0) {
3327629Ssam 		if (cmd == TIOCSETP || cmd == TIOCSETN)
3332395Swnj 			dhparam(unit);
3348566Sroot 		return (error);
3358566Sroot 	}
3368566Sroot 	switch (cmd) {
3377629Ssam 
338168Sbill 	case TIOCSBRK:
3392479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
340168Sbill 		break;
3417629Ssam 
342168Sbill 	case TIOCCBRK:
3432479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
344168Sbill 		break;
3457629Ssam 
346168Sbill 	case TIOCSDTR:
3472479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
348168Sbill 		break;
3497629Ssam 
350168Sbill 	case TIOCCDTR:
3512479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
352168Sbill 		break;
3537629Ssam 
354168Sbill 	default:
3558566Sroot 		return (ENOTTY);
356168Sbill 	}
3578566Sroot 	return (0);
35813Sbill }
35913Sbill 
36013Sbill /*
36113Sbill  * Set parameters from open or stty into the DH hardware
36213Sbill  * registers.
36313Sbill  */
3642395Swnj dhparam(unit)
3652395Swnj 	register int unit;
36613Sbill {
36713Sbill 	register struct tty *tp;
3682479Swnj 	register struct dhdevice *addr;
3692395Swnj 	register int lpar;
370300Sbill 	int s;
37113Sbill 
3722395Swnj 	tp = &dh11[unit];
3732479Swnj 	addr = (struct dhdevice *)tp->t_addr;
3742468Swnj 	/*
3752468Swnj 	 * Block interrupts so parameters will be set
3762468Swnj 	 * before the line interrupts.
3772468Swnj 	 */
378300Sbill 	s = spl5();
3792468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
38013Sbill 	if ((tp->t_ispeed)==0) {
3815406Swnj 		tp->t_state |= TS_HUPCLS;
3822479Swnj 		dmctl(unit, DML_OFF, DMSET);
38313Sbill 		return;
38413Sbill 	}
3852395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
3862468Swnj 	if ((tp->t_ispeed) == B134)
3872395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
3889549Ssam 	else if (tp->t_flags & (RAW|LITOUT))
3892395Swnj 		lpar |= BITS8;
39013Sbill 	else
3912395Swnj 		lpar |= BITS7|PENABLE;
39213Sbill 	if ((tp->t_flags&EVENP) == 0)
3932395Swnj 		lpar |= OPAR;
3942468Swnj 	if ((tp->t_ospeed) == B110)
3952395Swnj 		lpar |= TWOSB;
3962395Swnj 	addr->dhlpr = lpar;
397300Sbill 	splx(s);
39813Sbill }
39913Sbill 
40013Sbill /*
40113Sbill  * DH11 transmitter interrupt.
40213Sbill  * Restart each line which used to be active but has
40313Sbill  * terminated transmission since the last interrupt.
40413Sbill  */
4052395Swnj dhxint(dh)
4062395Swnj 	int dh;
40713Sbill {
40813Sbill 	register struct tty *tp;
4092479Swnj 	register struct dhdevice *addr;
41013Sbill 	short ttybit, bar, *sbar;
4112974Swnj 	register struct uba_device *ui;
4122468Swnj 	register int unit;
4132605Swnj 	u_short cntr;
41413Sbill 
4152395Swnj 	ui = dhinfo[dh];
4162479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4172456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4182456Swnj 		addr->un.dhcsr |= DH_CNI;
4192924Swnj 		printf("dh%d: NXM\n", dh);
420105Sbill 	}
4212395Swnj 	sbar = &dhsar[dh];
42213Sbill 	bar = *sbar & ~addr->dhbar;
4232395Swnj 	unit = dh * 16; ttybit = 1;
4242468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4252468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4262468Swnj 		if (bar & ttybit) {
42713Sbill 			*sbar &= ~ttybit;
42813Sbill 			bar &= ~ttybit;
4292395Swnj 			tp = &dh11[unit];
4305406Swnj 			tp->t_state &= ~TS_BUSY;
4315406Swnj 			if (tp->t_state&TS_FLUSH)
4325406Swnj 				tp->t_state &= ~TS_FLUSH;
433113Sbill 			else {
4342456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4352468Swnj 				/*
4362468Swnj 				 * Do arithmetic in a short to make up
4372468Swnj 				 * for lost 16&17 bits.
4382468Swnj 				 */
4392605Swnj 				cntr = addr->dhcar -
4402468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4413101Swnj 				ndflush(&tp->t_outq, (int)cntr);
442113Sbill 			}
443113Sbill 			if (tp->t_line)
44413Sbill 				(*linesw[tp->t_line].l_start)(tp);
445113Sbill 			else
44613Sbill 				dhstart(tp);
44713Sbill 		}
44813Sbill 	}
44913Sbill }
45013Sbill 
45113Sbill /*
45213Sbill  * Start (restart) transmission on the given DH11 line.
45313Sbill  */
45413Sbill dhstart(tp)
4552395Swnj 	register struct tty *tp;
45613Sbill {
4572479Swnj 	register struct dhdevice *addr;
4582468Swnj 	register int car, dh, unit, nch;
4592395Swnj 	int s;
46013Sbill 
4612468Swnj 	unit = minor(tp->t_dev);
4622468Swnj 	dh = unit >> 4;
4632468Swnj 	unit &= 0xf;
4642479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4652468Swnj 
46613Sbill 	/*
4672468Swnj 	 * Must hold interrupts in following code to prevent
4682468Swnj 	 * state of the tp from changing.
46913Sbill 	 */
47013Sbill 	s = spl5();
4712468Swnj 	/*
4722468Swnj 	 * If it's currently active, or delaying, no need to do anything.
4732468Swnj 	 */
4745406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
47513Sbill 		goto out;
4762468Swnj 	/*
4772468Swnj 	 * If there are sleepers, and output has drained below low
4782468Swnj 	 * water mark, wake up the sleepers.
4792468Swnj 	 */
4805406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
4815406Swnj 		if (tp->t_state&TS_ASLEEP) {
4825406Swnj 			tp->t_state &= ~TS_ASLEEP;
4835406Swnj 			wakeup((caddr_t)&tp->t_outq);
4845406Swnj 		}
4855406Swnj 		if (tp->t_wsel) {
4865406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
4875406Swnj 			tp->t_wsel = 0;
4885406Swnj 			tp->t_state &= ~TS_WCOLL;
4895406Swnj 		}
49013Sbill 	}
4912468Swnj 	/*
4922468Swnj 	 * Now restart transmission unless the output queue is
4932468Swnj 	 * empty.
4942468Swnj 	 */
49513Sbill 	if (tp->t_outq.c_cc == 0)
49613Sbill 		goto out;
4979549Ssam 	if (tp->t_flags & (RAW|LITOUT))
49813Sbill 		nch = ndqb(&tp->t_outq, 0);
4992395Swnj 	else {
50013Sbill 		nch = ndqb(&tp->t_outq, 0200);
5012468Swnj 		/*
5022468Swnj 		 * If first thing on queue is a delay process it.
5032468Swnj 		 */
50413Sbill 		if (nch == 0) {
50513Sbill 			nch = getc(&tp->t_outq);
5062468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5075406Swnj 			tp->t_state |= TS_TIMEOUT;
50813Sbill 			goto out;
50913Sbill 		}
51013Sbill 	}
5112468Swnj 	/*
5122468Swnj 	 * If characters to transmit, restart transmission.
5132468Swnj 	 */
51413Sbill 	if (nch) {
5152468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5162468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5173586Sroot 		/*
5183586Sroot 		 * The following nonsense with short word
5193586Sroot 		 * is to make sure the dhbar |= word below
5203586Sroot 		 * is done with an interlocking bisw2 instruction.
5213586Sroot 		 */
5223586Sroot 		{ short word = 1 << unit;
5233586Sroot 		dhsar[dh] |= word;
5242468Swnj 		addr->dhcar = car;
52513Sbill 		addr->dhbcr = -nch;
5263586Sroot 		addr->dhbar |= word;
5273586Sroot 		}
5285406Swnj 		tp->t_state |= TS_BUSY;
52913Sbill 	}
5302395Swnj out:
53113Sbill 	splx(s);
53213Sbill }
53313Sbill 
53413Sbill /*
5352468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
53613Sbill  */
53713Sbill /*ARGSUSED*/
53813Sbill dhstop(tp, flag)
5392468Swnj 	register struct tty *tp;
54013Sbill {
5412479Swnj 	register struct dhdevice *addr;
5422395Swnj 	register int unit, s;
54313Sbill 
5442479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5452468Swnj 	/*
5462468Swnj 	 * Block input/output interrupts while messing with state.
5472468Swnj 	 */
5482468Swnj 	s = spl5();
5495406Swnj 	if (tp->t_state & TS_BUSY) {
5502468Swnj 		/*
5512468Swnj 		 * Device is transmitting; stop output
5522468Swnj 		 * by selecting the line and setting the byte
5532468Swnj 		 * count to -1.  We will clean up later
5542468Swnj 		 * by examining the address where the dh stopped.
5552468Swnj 		 */
5562395Swnj 		unit = minor(tp->t_dev);
5572456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
5585406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
5595406Swnj 			tp->t_state |= TS_FLUSH;
560113Sbill 		addr->dhbcr = -1;
561113Sbill 	}
56213Sbill 	splx(s);
56313Sbill }
56413Sbill 
565168Sbill /*
566280Sbill  * Reset state of driver if UBA reset was necessary.
567280Sbill  * Reset the csrl and lpr registers on open lines, and
568280Sbill  * restart transmitters.
569280Sbill  */
5702395Swnj dhreset(uban)
5712468Swnj 	int uban;
572280Sbill {
5732395Swnj 	register int dh, unit;
574280Sbill 	register struct tty *tp;
5752974Swnj 	register struct uba_device *ui;
5762421Skre 	int i;
577280Sbill 
5782421Skre 	if (dh_ubinfo[uban] == 0)
5792421Skre 		return;
5802421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
5812770Swnj 	    512+nclist*sizeof (struct cblock), 0);
5822421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
5832395Swnj 	dh = 0;
5842643Swnj 	for (dh = 0; dh < NDH; dh++) {
5852421Skre 		ui = dhinfo[dh];
5862421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
5872421Skre 			continue;
5882924Swnj 		printf(" dh%d", dh);
5892479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
5902479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
5912421Skre 		unit = dh * 16;
5922421Skre 		for (i = 0; i < 16; i++) {
5932421Skre 			tp = &dh11[unit];
5945406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
5952421Skre 				dhparam(unit);
5962479Swnj 				dmctl(unit, DML_ON, DMSET);
5975406Swnj 				tp->t_state &= ~TS_BUSY;
5982421Skre 				dhstart(tp);
5992421Skre 			}
6002421Skre 			unit++;
601300Sbill 		}
602300Sbill 	}
603300Sbill 	dhtimer();
604280Sbill }
6052395Swnj 
6062468Swnj /*
6072468Swnj  * At software clock interrupt time or after a UNIBUS reset
6082468Swnj  * empty all the dh silos.
6092468Swnj  */
6102456Swnj dhtimer()
6112456Swnj {
6122456Swnj 	register int dh;
6138159Sroot 	register int s = spl5();
6142456Swnj 
6152643Swnj 	for (dh = 0; dh < NDH; dh++)
6162456Swnj 		dhrint(dh);
6178159Sroot 	splx(s);
6182456Swnj }
6192456Swnj 
6202468Swnj /*
6212479Swnj  * Turn on the line associated with dh dev.
6222468Swnj  */
6232468Swnj dmopen(dev)
6242468Swnj 	dev_t dev;
6252468Swnj {
6262468Swnj 	register struct tty *tp;
6272468Swnj 	register struct dmdevice *addr;
6282974Swnj 	register struct uba_device *ui;
6292468Swnj 	register int unit;
6302468Swnj 	register int dm;
6313792Swnj 	int s;
6322468Swnj 
6332468Swnj 	unit = minor(dev);
6342479Swnj 	dm = unit >> 4;
6352468Swnj 	tp = &dh11[unit];
6362566Swnj 	unit &= 0xf;
6372643Swnj 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
6382566Swnj 	    (dhsoftCAR[dm]&(1<<unit))) {
6395406Swnj 		tp->t_state |= TS_CARR_ON;
6402468Swnj 		return;
6412468Swnj 	}
6422468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6433792Swnj 	s = spl5();
6442479Swnj 	addr->dmcsr &= ~DM_SE;
6452479Swnj 	while (addr->dmcsr & DM_BUSY)
6462468Swnj 		;
6472566Swnj 	addr->dmcsr = unit;
6482479Swnj 	addr->dmlstat = DML_ON;
6492479Swnj 	if (addr->dmlstat&DML_CAR)
6505406Swnj 		tp->t_state |= TS_CARR_ON;
6513792Swnj 	addr->dmcsr = DM_IE|DM_SE;
6525406Swnj 	while ((tp->t_state&TS_CARR_ON)==0)
6532468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
6543792Swnj 	splx(s);
6552468Swnj }
6562468Swnj 
6572468Swnj /*
6582468Swnj  * Dump control bits into the DM registers.
6592468Swnj  */
6602468Swnj dmctl(dev, bits, how)
6612468Swnj 	dev_t dev;
6622468Swnj 	int bits, how;
6632468Swnj {
6642974Swnj 	register struct uba_device *ui;
6652468Swnj 	register struct dmdevice *addr;
6662468Swnj 	register int unit, s;
6672468Swnj 	int dm;
6682468Swnj 
6692468Swnj 	unit = minor(dev);
6702468Swnj 	dm = unit >> 4;
6712468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
6722468Swnj 		return;
6732468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6742468Swnj 	s = spl5();
6752479Swnj 	addr->dmcsr &= ~DM_SE;
6762479Swnj 	while (addr->dmcsr & DM_BUSY)
6772468Swnj 		;
6782468Swnj 	addr->dmcsr = unit & 0xf;
6792468Swnj 	switch(how) {
6802468Swnj 	case DMSET:
6812468Swnj 		addr->dmlstat = bits;
6822468Swnj 		break;
6832468Swnj 	case DMBIS:
6842468Swnj 		addr->dmlstat |= bits;
6852468Swnj 		break;
6862468Swnj 	case DMBIC:
6872468Swnj 		addr->dmlstat &= ~bits;
6882468Swnj 		break;
6892468Swnj 	}
6903792Swnj 	addr->dmcsr = DM_IE|DM_SE;
6912468Swnj 	splx(s);
6922468Swnj }
6932468Swnj 
6942468Swnj /*
6952468Swnj  * DM11 interrupt; deal with carrier transitions.
6962468Swnj  */
6972468Swnj dmintr(dm)
6982468Swnj 	register int dm;
6992468Swnj {
7002974Swnj 	register struct uba_device *ui;
7012468Swnj 	register struct tty *tp;
7022468Swnj 	register struct dmdevice *addr;
7032468Swnj 
7042468Swnj 	ui = dminfo[dm];
7052479Swnj 	if (ui == 0)
7062479Swnj 		return;
7072468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7083997Sroot 	if (addr->dmcsr&DM_DONE) {
7093997Sroot 		if (addr->dmcsr&DM_CF) {
7103997Sroot 			tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
7113997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7129549Ssam 			if ((tp->t_state&TS_WOPEN) == 0 &&
7139605Ssam 			    (tp->t_flags & MDMBUF)) {
7143997Sroot 				if (addr->dmlstat & DML_CAR) {
7155406Swnj 					tp->t_state &= ~TS_TTSTOP;
7163997Sroot 					ttstart(tp);
7175406Swnj 				} else if ((tp->t_state&TS_TTSTOP) == 0) {
7185406Swnj 					tp->t_state |= TS_TTSTOP;
7193997Sroot 					dhstop(tp, 0);
7203997Sroot 				}
7213997Sroot 			} else if ((addr->dmlstat&DML_CAR)==0) {
7225406Swnj 				if ((tp->t_state&TS_WOPEN)==0 &&
7239605Ssam 				    (tp->t_flags & NOHANG) == 0) {
7243997Sroot 					gsignal(tp->t_pgrp, SIGHUP);
7253997Sroot 					gsignal(tp->t_pgrp, SIGCONT);
7263997Sroot 					addr->dmlstat = 0;
72712775Ssam 					ttyflush(tp, FREAD|FWRITE);
7283997Sroot 				}
7295406Swnj 				tp->t_state &= ~TS_CARR_ON;
7303997Sroot 			} else
7315406Swnj 				tp->t_state |= TS_CARR_ON;
7323997Sroot 		}
7333997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7342468Swnj 	}
7352468Swnj }
7362625Swnj #endif
737