xref: /csrg-svn/sys/vax/uba/dh.c (revision 10018)
1*10018Ssam /*	dh.c	4.57	82/12/30	*/
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"
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"
24*10018Ssam #include "../vaxuba/dhreg.h"
25*10018Ssam #include "../vaxuba/dmreg.h"
268472Sroot 
27113Sbill #include "../h/bk.h"
281561Sbill #include "../h/clist.h"
292468Swnj #include "../h/file.h"
307725Sroot #include "../h/uio.h"
3113Sbill 
322468Swnj /*
332479Swnj  * Definition of the driver for the auto-configuration program.
342479Swnj  * There is one definition for the dh and one for the dm.
352468Swnj  */
362605Swnj int	dhprobe(), dhattach(), dhrint(), dhxint();
372974Swnj struct	uba_device *dhinfo[NDH];
382395Swnj u_short	dhstd[] = { 0 };
392395Swnj struct	uba_driver dhdriver =
402605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
412395Swnj 
422605Swnj int	dmprobe(), dmattach(), dmintr();
432974Swnj struct	uba_device *dminfo[NDH];
442479Swnj u_short	dmstd[] = { 0 };
452479Swnj struct	uba_driver dmdriver =
462605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
4713Sbill 
486615Ssam #ifndef	PORTSELECTOR
496615Ssam #define	ISPEED	B300
506615Ssam #define	IFLAGS	(EVENP|ODDP|ECHO)
516615Ssam #else
526615Ssam #define	ISPEED	B4800
536615Ssam #define	IFLAGS	(EVENP|ODDP)
546615Ssam #endif
556615Ssam 
5613Sbill /*
572479Swnj  * Local variables for the driver
5813Sbill  */
592643Swnj short	dhsar[NDH];			/* software copy of last bar */
602643Swnj short	dhsoftCAR[NDH];
6113Sbill 
622643Swnj struct	tty dh11[NDH*16];
632643Swnj int	ndh11	= NDH*16;
642479Swnj int	dhact;				/* mask of active dh's */
652479Swnj int	dhstart(), ttrstrt();
6613Sbill 
672479Swnj /*
682479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
692479Swnj  * The UBACVT macro converts a clist space address for unibus uban
702479Swnj  * into an i/o space address for the DMA routine.
712479Swnj  */
722479Swnj int	dh_ubinfo[MAXNUBA];		/* info about allocated unibus map */
732479Swnj int	cbase[MAXNUBA];			/* base address in unibus map */
742479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
7513Sbill 
762456Swnj /*
772456Swnj  * Routine for configuration to force a dh to interrupt.
782456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
792456Swnj  */
802468Swnj /*ARGSUSED*/
812605Swnj dhprobe(reg)
822395Swnj 	caddr_t reg;
832395Swnj {
842468Swnj 	register int br, cvec;		/* these are ``value-result'' */
852479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
862395Swnj 
872605Swnj #ifdef lint
882605Swnj 	br = 0; cvec = br; br = cvec;
897384Sroot 	if (ndh11 == 0) ndh11 = 1;
904932Swnj 	dhrint(0); dhxint(0);
912605Swnj #endif
922696Swnj #ifndef notdef
932566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
946380Swnj 	DELAY(1000);
957384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
962566Swnj 	dhaddr->un.dhcsr = 0;
972566Swnj #else
982456Swnj 	dhaddr->un.dhcsr = DH_TIE;
992456Swnj 	DELAY(5);
1002456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1012421Skre 	dhaddr->dhbcr = -1;
1022456Swnj 	dhaddr->dhcar = 0;
1032421Skre 	dhaddr->dhbar = 1;
1042456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1052421Skre 	dhaddr->un.dhcsr = 0;
1062456Swnj 	if (cvec && cvec != 0x200)
1072456Swnj 		cvec -= 4;		/* transmit -> receive */
1082482Swnj #endif
1097408Skre 	return (sizeof (struct dhdevice));
1102395Swnj }
1112395Swnj 
1122456Swnj /*
1132605Swnj  * Routine called to attach a dh.
1142456Swnj  */
1152605Swnj dhattach(ui)
1162974Swnj 	struct uba_device *ui;
1172395Swnj {
1182395Swnj 
1192566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1202395Swnj }
1212395Swnj 
12213Sbill /*
1232479Swnj  * Configuration routine to cause a dm to interrupt.
1242479Swnj  */
1252605Swnj dmprobe(reg)
1262605Swnj 	caddr_t reg;
1272479Swnj {
1282479Swnj 	register int br, vec;			/* value-result */
1292605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1302479Swnj 
1312605Swnj #ifdef lint
1323101Swnj 	br = 0; vec = br; br = vec;
1336185Ssam 	dmintr(0);
1342605Swnj #endif
1352479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1362479Swnj 	DELAY(20);
1372479Swnj 	dmaddr->dmcsr = 0;
1382605Swnj 	return (1);
1392479Swnj }
1402479Swnj 
1412605Swnj /*ARGSUSED*/
1422605Swnj dmattach(ui)
1432974Swnj 	struct uba_device *ui;
1442479Swnj {
1452479Swnj 
1462479Swnj 	/* no local state to set up */
1472479Swnj }
1482479Swnj 
1492479Swnj /*
1502468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1512468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1522468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
15313Sbill  */
15413Sbill /*ARGSUSED*/
15513Sbill dhopen(dev, flag)
1562395Swnj 	dev_t dev;
15713Sbill {
15813Sbill 	register struct tty *tp;
1592395Swnj 	register int unit, dh;
1602479Swnj 	register struct dhdevice *addr;
1612974Swnj 	register struct uba_device *ui;
16213Sbill 	int s;
16313Sbill 
1642395Swnj 	unit = minor(dev);
1652395Swnj 	dh = unit >> 4;
1668566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
1678566Sroot 		return (ENXIO);
1682395Swnj 	tp = &dh11[unit];
1698566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
1708566Sroot 		return (EBUSY);
1712479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
17213Sbill 	tp->t_addr = (caddr_t)addr;
17313Sbill 	tp->t_oproc = dhstart;
1745406Swnj 	tp->t_state |= TS_WOPEN;
1752468Swnj 	/*
1762468Swnj 	 * While setting up state for this uba and this dh,
1772468Swnj 	 * block uba resets which can clear the state.
1782468Swnj 	 */
1792468Swnj 	s = spl5();
1802421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
181717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
1822395Swnj 		dh_ubinfo[ui->ui_ubanum] =
1832421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
1842770Swnj 			512+nclist*sizeof(struct cblock), 0);
1852456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
18613Sbill 	}
1872456Swnj 	if ((dhact&(1<<dh)) == 0) {
1882456Swnj 		addr->un.dhcsr |= DH_IE;
1892468Swnj 		dhact |= (1<<dh);
1902456Swnj 		addr->dhsilo = 16;
1912456Swnj 	}
19213Sbill 	splx(s);
1932468Swnj 	/*
1942468Swnj 	 * If this is first open, initialze tty state to default.
1952468Swnj 	 */
1965406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
19713Sbill 		ttychars(tp);
1986615Ssam #ifndef PORTSELECTOR
199168Sbill 		if (tp->t_ispeed == 0) {
2006615Ssam #endif
2016615Ssam 			tp->t_ispeed = ISPEED;
2026615Ssam 			tp->t_ospeed = ISPEED;
2036615Ssam 			tp->t_flags = IFLAGS;
2046615Ssam #ifndef PORTSELECTOR
205168Sbill 		}
2066615Ssam #endif
2072395Swnj 		dhparam(unit);
20813Sbill 	}
2092468Swnj 	/*
2102468Swnj 	 * Wait for carrier, then process line discipline specific open.
2112468Swnj 	 */
21213Sbill 	dmopen(dev);
2138566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
21413Sbill }
21513Sbill 
21613Sbill /*
2172468Swnj  * Close a DH11 line, turning off the DM11.
21813Sbill  */
21913Sbill /*ARGSUSED*/
22013Sbill dhclose(dev, flag)
2212395Swnj 	dev_t dev;
2222395Swnj 	int flag;
22313Sbill {
22413Sbill 	register struct tty *tp;
2252395Swnj 	register unit;
22613Sbill 
2272395Swnj 	unit = minor(dev);
2282395Swnj 	tp = &dh11[unit];
22913Sbill 	(*linesw[tp->t_line].l_close)(tp);
2302479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
2315406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
2322479Swnj 		dmctl(unit, DML_OFF, DMSET);
23313Sbill 	ttyclose(tp);
23413Sbill }
23513Sbill 
2367725Sroot dhread(dev, uio)
2372395Swnj 	dev_t dev;
2387725Sroot 	struct uio *uio;
23913Sbill {
2408490Sroot 	register struct tty *tp = &dh11[minor(dev)];
24113Sbill 
2427725Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
24313Sbill }
24413Sbill 
2457831Sroot dhwrite(dev, uio)
2462395Swnj 	dev_t dev;
2477831Sroot 	struct uio *uio;
24813Sbill {
2498490Sroot 	register struct tty *tp = &dh11[minor(dev)];
25013Sbill 
2518490Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
25213Sbill }
25313Sbill 
25413Sbill /*
25513Sbill  * DH11 receiver interrupt.
25613Sbill  */
2572395Swnj dhrint(dh)
2582395Swnj 	int dh;
25913Sbill {
26013Sbill 	register struct tty *tp;
2612395Swnj 	register c;
2622479Swnj 	register struct dhdevice *addr;
263117Sbill 	register struct tty *tp0;
2642974Swnj 	register struct uba_device *ui;
2652924Swnj 	int overrun = 0;
26613Sbill 
2672395Swnj 	ui = dhinfo[dh];
2682479Swnj 	if (ui == 0 || ui->ui_alive == 0)
2692479Swnj 		return;
2702479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
2712468Swnj 	tp0 = &dh11[dh<<4];
2722468Swnj 	/*
2732468Swnj 	 * Loop fetching characters from the silo for this
2742468Swnj 	 * dh until there are no more in the silo.
2752468Swnj 	 */
2762468Swnj 	while ((c = addr->dhrcr) < 0) {
2772468Swnj 		tp = tp0 + ((c>>8)&0xf);
2786615Ssam #ifndef PORTSELECTOR
2795406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
2806615Ssam #else
2816615Ssam 		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
2826615Ssam #endif
28313Sbill 			wakeup((caddr_t)tp);
28413Sbill 			continue;
28513Sbill 		}
2862468Swnj 		if (c & DH_PE)
28713Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
28813Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
28913Sbill 				continue;
2902924Swnj 		if ((c & DH_DO) && overrun == 0) {
2912924Swnj 			printf("dh%d: silo overflow\n", dh);
2922924Swnj 			overrun = 1;
2932924Swnj 		}
2942468Swnj 		if (c & DH_FE)
2952468Swnj 			/*
2962468Swnj 			 * At framing error (break) generate
2972468Swnj 			 * a null (in raw mode, for getty), or a
2982468Swnj 			 * interrupt (in cooked/cbreak mode).
2992468Swnj 			 */
30013Sbill 			if (tp->t_flags&RAW)
3012468Swnj 				c = 0;
30213Sbill 			else
3039549Ssam 				c = tp->t_intrc;
3042730Swnj #if NBK > 0
305139Sbill 		if (tp->t_line == NETLDISC) {
306117Sbill 			c &= 0177;
307168Sbill 			BKINPUT(c, tp);
308117Sbill 		} else
3092730Swnj #endif
3102468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
31113Sbill 	}
31213Sbill }
31313Sbill 
31413Sbill /*
3152468Swnj  * Ioctl for DH11.
31613Sbill  */
31713Sbill /*ARGSUSED*/
3187629Ssam dhioctl(dev, cmd, data, flag)
3197629Ssam 	caddr_t data;
32013Sbill {
32113Sbill 	register struct tty *tp;
3228566Sroot 	register int unit = minor(dev);
3238566Sroot 	int error;
32413Sbill 
3252395Swnj 	tp = &dh11[unit];
3268566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3278566Sroot 	if (error >= 0)
3288566Sroot 		return (error);
3298566Sroot 	error = ttioctl(tp, cmd, data, flag);
3308566Sroot 	if (error >= 0) {
3317629Ssam 		if (cmd == TIOCSETP || cmd == TIOCSETN)
3322395Swnj 			dhparam(unit);
3338566Sroot 		return (error);
3348566Sroot 	}
3358566Sroot 	switch (cmd) {
3367629Ssam 
337168Sbill 	case TIOCSBRK:
3382479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
339168Sbill 		break;
3407629Ssam 
341168Sbill 	case TIOCCBRK:
3422479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
343168Sbill 		break;
3447629Ssam 
345168Sbill 	case TIOCSDTR:
3462479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
347168Sbill 		break;
3487629Ssam 
349168Sbill 	case TIOCCDTR:
3502479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
351168Sbill 		break;
3527629Ssam 
353168Sbill 	default:
3548566Sroot 		return (ENOTTY);
355168Sbill 	}
3568566Sroot 	return (0);
35713Sbill }
35813Sbill 
35913Sbill /*
36013Sbill  * Set parameters from open or stty into the DH hardware
36113Sbill  * registers.
36213Sbill  */
3632395Swnj dhparam(unit)
3642395Swnj 	register int unit;
36513Sbill {
36613Sbill 	register struct tty *tp;
3672479Swnj 	register struct dhdevice *addr;
3682395Swnj 	register int lpar;
369300Sbill 	int s;
37013Sbill 
3712395Swnj 	tp = &dh11[unit];
3722479Swnj 	addr = (struct dhdevice *)tp->t_addr;
3732468Swnj 	/*
3742468Swnj 	 * Block interrupts so parameters will be set
3752468Swnj 	 * before the line interrupts.
3762468Swnj 	 */
377300Sbill 	s = spl5();
3782468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
37913Sbill 	if ((tp->t_ispeed)==0) {
3805406Swnj 		tp->t_state |= TS_HUPCLS;
3812479Swnj 		dmctl(unit, DML_OFF, DMSET);
38213Sbill 		return;
38313Sbill 	}
3842395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
3852468Swnj 	if ((tp->t_ispeed) == B134)
3862395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
3879549Ssam 	else if (tp->t_flags & (RAW|LITOUT))
3882395Swnj 		lpar |= BITS8;
38913Sbill 	else
3902395Swnj 		lpar |= BITS7|PENABLE;
39113Sbill 	if ((tp->t_flags&EVENP) == 0)
3922395Swnj 		lpar |= OPAR;
3932468Swnj 	if ((tp->t_ospeed) == B110)
3942395Swnj 		lpar |= TWOSB;
3952395Swnj 	addr->dhlpr = lpar;
396300Sbill 	splx(s);
39713Sbill }
39813Sbill 
39913Sbill /*
40013Sbill  * DH11 transmitter interrupt.
40113Sbill  * Restart each line which used to be active but has
40213Sbill  * terminated transmission since the last interrupt.
40313Sbill  */
4042395Swnj dhxint(dh)
4052395Swnj 	int dh;
40613Sbill {
40713Sbill 	register struct tty *tp;
4082479Swnj 	register struct dhdevice *addr;
40913Sbill 	short ttybit, bar, *sbar;
4102974Swnj 	register struct uba_device *ui;
4112468Swnj 	register int unit;
4122605Swnj 	u_short cntr;
41313Sbill 
4142395Swnj 	ui = dhinfo[dh];
4152479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4162456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4172456Swnj 		addr->un.dhcsr |= DH_CNI;
4182924Swnj 		printf("dh%d: NXM\n", dh);
419105Sbill 	}
4202395Swnj 	sbar = &dhsar[dh];
42113Sbill 	bar = *sbar & ~addr->dhbar;
4222395Swnj 	unit = dh * 16; ttybit = 1;
4232468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4242468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4252468Swnj 		if (bar & ttybit) {
42613Sbill 			*sbar &= ~ttybit;
42713Sbill 			bar &= ~ttybit;
4282395Swnj 			tp = &dh11[unit];
4295406Swnj 			tp->t_state &= ~TS_BUSY;
4305406Swnj 			if (tp->t_state&TS_FLUSH)
4315406Swnj 				tp->t_state &= ~TS_FLUSH;
432113Sbill 			else {
4332456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4342468Swnj 				/*
4352468Swnj 				 * Do arithmetic in a short to make up
4362468Swnj 				 * for lost 16&17 bits.
4372468Swnj 				 */
4382605Swnj 				cntr = addr->dhcar -
4392468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4403101Swnj 				ndflush(&tp->t_outq, (int)cntr);
441113Sbill 			}
442113Sbill 			if (tp->t_line)
44313Sbill 				(*linesw[tp->t_line].l_start)(tp);
444113Sbill 			else
44513Sbill 				dhstart(tp);
44613Sbill 		}
44713Sbill 	}
44813Sbill }
44913Sbill 
45013Sbill /*
45113Sbill  * Start (restart) transmission on the given DH11 line.
45213Sbill  */
45313Sbill dhstart(tp)
4542395Swnj 	register struct tty *tp;
45513Sbill {
4562479Swnj 	register struct dhdevice *addr;
4572468Swnj 	register int car, dh, unit, nch;
4582395Swnj 	int s;
45913Sbill 
4602468Swnj 	unit = minor(tp->t_dev);
4612468Swnj 	dh = unit >> 4;
4622468Swnj 	unit &= 0xf;
4632479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4642468Swnj 
46513Sbill 	/*
4662468Swnj 	 * Must hold interrupts in following code to prevent
4672468Swnj 	 * state of the tp from changing.
46813Sbill 	 */
46913Sbill 	s = spl5();
4702468Swnj 	/*
4712468Swnj 	 * If it's currently active, or delaying, no need to do anything.
4722468Swnj 	 */
4735406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
47413Sbill 		goto out;
4752468Swnj 	/*
4762468Swnj 	 * If there are sleepers, and output has drained below low
4772468Swnj 	 * water mark, wake up the sleepers.
4782468Swnj 	 */
4795406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
4805406Swnj 		if (tp->t_state&TS_ASLEEP) {
4815406Swnj 			tp->t_state &= ~TS_ASLEEP;
4825406Swnj 			wakeup((caddr_t)&tp->t_outq);
4835406Swnj 		}
4845406Swnj 		if (tp->t_wsel) {
4855406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
4865406Swnj 			tp->t_wsel = 0;
4875406Swnj 			tp->t_state &= ~TS_WCOLL;
4885406Swnj 		}
48913Sbill 	}
4902468Swnj 	/*
4912468Swnj 	 * Now restart transmission unless the output queue is
4922468Swnj 	 * empty.
4932468Swnj 	 */
49413Sbill 	if (tp->t_outq.c_cc == 0)
49513Sbill 		goto out;
4969549Ssam 	if (tp->t_flags & (RAW|LITOUT))
49713Sbill 		nch = ndqb(&tp->t_outq, 0);
4982395Swnj 	else {
49913Sbill 		nch = ndqb(&tp->t_outq, 0200);
5002468Swnj 		/*
5012468Swnj 		 * If first thing on queue is a delay process it.
5022468Swnj 		 */
50313Sbill 		if (nch == 0) {
50413Sbill 			nch = getc(&tp->t_outq);
5052468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5065406Swnj 			tp->t_state |= TS_TIMEOUT;
50713Sbill 			goto out;
50813Sbill 		}
50913Sbill 	}
5102468Swnj 	/*
5112468Swnj 	 * If characters to transmit, restart transmission.
5122468Swnj 	 */
51313Sbill 	if (nch) {
5142468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5152468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5163586Sroot 		/*
5173586Sroot 		 * The following nonsense with short word
5183586Sroot 		 * is to make sure the dhbar |= word below
5193586Sroot 		 * is done with an interlocking bisw2 instruction.
5203586Sroot 		 */
5213586Sroot 		{ short word = 1 << unit;
5223586Sroot 		dhsar[dh] |= word;
5232468Swnj 		addr->dhcar = car;
52413Sbill 		addr->dhbcr = -nch;
5253586Sroot 		addr->dhbar |= word;
5263586Sroot 		}
5275406Swnj 		tp->t_state |= TS_BUSY;
52813Sbill 	}
5292395Swnj out:
53013Sbill 	splx(s);
53113Sbill }
53213Sbill 
53313Sbill /*
5342468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
53513Sbill  */
53613Sbill /*ARGSUSED*/
53713Sbill dhstop(tp, flag)
5382468Swnj 	register struct tty *tp;
53913Sbill {
5402479Swnj 	register struct dhdevice *addr;
5412395Swnj 	register int unit, s;
54213Sbill 
5432479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5442468Swnj 	/*
5452468Swnj 	 * Block input/output interrupts while messing with state.
5462468Swnj 	 */
5472468Swnj 	s = spl5();
5485406Swnj 	if (tp->t_state & TS_BUSY) {
5492468Swnj 		/*
5502468Swnj 		 * Device is transmitting; stop output
5512468Swnj 		 * by selecting the line and setting the byte
5522468Swnj 		 * count to -1.  We will clean up later
5532468Swnj 		 * by examining the address where the dh stopped.
5542468Swnj 		 */
5552395Swnj 		unit = minor(tp->t_dev);
5562456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
5575406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
5585406Swnj 			tp->t_state |= TS_FLUSH;
559113Sbill 		addr->dhbcr = -1;
560113Sbill 	}
56113Sbill 	splx(s);
56213Sbill }
56313Sbill 
564168Sbill /*
565280Sbill  * Reset state of driver if UBA reset was necessary.
566280Sbill  * Reset the csrl and lpr registers on open lines, and
567280Sbill  * restart transmitters.
568280Sbill  */
5692395Swnj dhreset(uban)
5702468Swnj 	int uban;
571280Sbill {
5722395Swnj 	register int dh, unit;
573280Sbill 	register struct tty *tp;
5742974Swnj 	register struct uba_device *ui;
5752421Skre 	int i;
576280Sbill 
5772421Skre 	if (dh_ubinfo[uban] == 0)
5782421Skre 		return;
5792421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
5802770Swnj 	    512+nclist*sizeof (struct cblock), 0);
5812421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
5822395Swnj 	dh = 0;
5832643Swnj 	for (dh = 0; dh < NDH; dh++) {
5842421Skre 		ui = dhinfo[dh];
5852421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
5862421Skre 			continue;
5872924Swnj 		printf(" dh%d", dh);
5882479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
5892479Swnj 		((struct dhdevice *)ui->ui_addr)->dhsilo = 16;
5902421Skre 		unit = dh * 16;
5912421Skre 		for (i = 0; i < 16; i++) {
5922421Skre 			tp = &dh11[unit];
5935406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
5942421Skre 				dhparam(unit);
5952479Swnj 				dmctl(unit, DML_ON, DMSET);
5965406Swnj 				tp->t_state &= ~TS_BUSY;
5972421Skre 				dhstart(tp);
5982421Skre 			}
5992421Skre 			unit++;
600300Sbill 		}
601300Sbill 	}
602300Sbill 	dhtimer();
603280Sbill }
6042395Swnj 
6052468Swnj /*
6062468Swnj  * At software clock interrupt time or after a UNIBUS reset
6072468Swnj  * empty all the dh silos.
6082468Swnj  */
6092456Swnj dhtimer()
6102456Swnj {
6112456Swnj 	register int dh;
6128159Sroot 	register int s = spl5();
6132456Swnj 
6142643Swnj 	for (dh = 0; dh < NDH; dh++)
6152456Swnj 		dhrint(dh);
6168159Sroot 	splx(s);
6172456Swnj }
6182456Swnj 
6192468Swnj /*
6202479Swnj  * Turn on the line associated with dh dev.
6212468Swnj  */
6222468Swnj dmopen(dev)
6232468Swnj 	dev_t dev;
6242468Swnj {
6252468Swnj 	register struct tty *tp;
6262468Swnj 	register struct dmdevice *addr;
6272974Swnj 	register struct uba_device *ui;
6282468Swnj 	register int unit;
6292468Swnj 	register int dm;
6303792Swnj 	int s;
6312468Swnj 
6322468Swnj 	unit = minor(dev);
6332479Swnj 	dm = unit >> 4;
6342468Swnj 	tp = &dh11[unit];
6352566Swnj 	unit &= 0xf;
6362643Swnj 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 ||
6372566Swnj 	    (dhsoftCAR[dm]&(1<<unit))) {
6385406Swnj 		tp->t_state |= TS_CARR_ON;
6392468Swnj 		return;
6402468Swnj 	}
6412468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6423792Swnj 	s = spl5();
6432479Swnj 	addr->dmcsr &= ~DM_SE;
6442479Swnj 	while (addr->dmcsr & DM_BUSY)
6452468Swnj 		;
6462566Swnj 	addr->dmcsr = unit;
6472479Swnj 	addr->dmlstat = DML_ON;
6482479Swnj 	if (addr->dmlstat&DML_CAR)
6495406Swnj 		tp->t_state |= TS_CARR_ON;
6503792Swnj 	addr->dmcsr = DM_IE|DM_SE;
6515406Swnj 	while ((tp->t_state&TS_CARR_ON)==0)
6522468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
6533792Swnj 	splx(s);
6542468Swnj }
6552468Swnj 
6562468Swnj /*
6572468Swnj  * Dump control bits into the DM registers.
6582468Swnj  */
6592468Swnj dmctl(dev, bits, how)
6602468Swnj 	dev_t dev;
6612468Swnj 	int bits, how;
6622468Swnj {
6632974Swnj 	register struct uba_device *ui;
6642468Swnj 	register struct dmdevice *addr;
6652468Swnj 	register int unit, s;
6662468Swnj 	int dm;
6672468Swnj 
6682468Swnj 	unit = minor(dev);
6692468Swnj 	dm = unit >> 4;
6702468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
6712468Swnj 		return;
6722468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6732468Swnj 	s = spl5();
6742479Swnj 	addr->dmcsr &= ~DM_SE;
6752479Swnj 	while (addr->dmcsr & DM_BUSY)
6762468Swnj 		;
6772468Swnj 	addr->dmcsr = unit & 0xf;
6782468Swnj 	switch(how) {
6792468Swnj 	case DMSET:
6802468Swnj 		addr->dmlstat = bits;
6812468Swnj 		break;
6822468Swnj 	case DMBIS:
6832468Swnj 		addr->dmlstat |= bits;
6842468Swnj 		break;
6852468Swnj 	case DMBIC:
6862468Swnj 		addr->dmlstat &= ~bits;
6872468Swnj 		break;
6882468Swnj 	}
6893792Swnj 	addr->dmcsr = DM_IE|DM_SE;
6902468Swnj 	splx(s);
6912468Swnj }
6922468Swnj 
6932468Swnj /*
6942468Swnj  * DM11 interrupt; deal with carrier transitions.
6952468Swnj  */
6962468Swnj dmintr(dm)
6972468Swnj 	register int dm;
6982468Swnj {
6992974Swnj 	register struct uba_device *ui;
7002468Swnj 	register struct tty *tp;
7012468Swnj 	register struct dmdevice *addr;
7022468Swnj 
7032468Swnj 	ui = dminfo[dm];
7042479Swnj 	if (ui == 0)
7052479Swnj 		return;
7062468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7073997Sroot 	if (addr->dmcsr&DM_DONE) {
7083997Sroot 		if (addr->dmcsr&DM_CF) {
7093997Sroot 			tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
7103997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7119549Ssam 			if ((tp->t_state&TS_WOPEN) == 0 &&
7129605Ssam 			    (tp->t_flags & MDMBUF)) {
7133997Sroot 				if (addr->dmlstat & DML_CAR) {
7145406Swnj 					tp->t_state &= ~TS_TTSTOP;
7153997Sroot 					ttstart(tp);
7165406Swnj 				} else if ((tp->t_state&TS_TTSTOP) == 0) {
7175406Swnj 					tp->t_state |= TS_TTSTOP;
7183997Sroot 					dhstop(tp, 0);
7193997Sroot 				}
7203997Sroot 			} else if ((addr->dmlstat&DML_CAR)==0) {
7215406Swnj 				if ((tp->t_state&TS_WOPEN)==0 &&
7229605Ssam 				    (tp->t_flags & NOHANG) == 0) {
7233997Sroot 					gsignal(tp->t_pgrp, SIGHUP);
7243997Sroot 					gsignal(tp->t_pgrp, SIGCONT);
7253997Sroot 					addr->dmlstat = 0;
7263997Sroot 					flushtty(tp, FREAD|FWRITE);
7273997Sroot 				}
7285406Swnj 				tp->t_state &= ~TS_CARR_ON;
7293997Sroot 			} else
7305406Swnj 				tp->t_state |= TS_CARR_ON;
7313997Sroot 		}
7323997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7332468Swnj 	}
7342468Swnj }
7352625Swnj #endif
736