xref: /csrg-svn/sys/vax/uba/dh.c (revision 21954)
1*21954Skarels /*	dh.c	6.8	85/06/04	*/
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"
1116062Skarels #include "uba.h"
1217122Sbloom #include "param.h"
1317122Sbloom #include "conf.h"
1417122Sbloom #include "dir.h"
1517122Sbloom #include "user.h"
1617122Sbloom #include "proc.h"
1717122Sbloom #include "ioctl.h"
1817122Sbloom #include "tty.h"
1917122Sbloom #include "map.h"
2017122Sbloom #include "buf.h"
2117122Sbloom #include "vm.h"
2217122Sbloom #include "kernel.h"
2318311Sralph #include "syslog.h"
248472Sroot 
2517122Sbloom #include "ubareg.h"
2617122Sbloom #include "ubavar.h"
2717122Sbloom #include "dhreg.h"
2817122Sbloom #include "dmreg.h"
298472Sroot 
3017122Sbloom #include "bkmac.h"
3117122Sbloom #include "clist.h"
3217122Sbloom #include "file.h"
3317122Sbloom #include "uio.h"
3413Sbill 
352468Swnj /*
362479Swnj  * Definition of the driver for the auto-configuration program.
372479Swnj  * There is one definition for the dh and one for the dm.
382468Swnj  */
3916190Skarels int	dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
402974Swnj struct	uba_device *dhinfo[NDH];
412395Swnj u_short	dhstd[] = { 0 };
422395Swnj struct	uba_driver dhdriver =
432605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
442395Swnj 
452605Swnj int	dmprobe(), dmattach(), dmintr();
462974Swnj struct	uba_device *dminfo[NDH];
472479Swnj u_short	dmstd[] = { 0 };
482479Swnj struct	uba_driver dmdriver =
492605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
5013Sbill 
516615Ssam #ifndef	PORTSELECTOR
526615Ssam #define	ISPEED	B300
536615Ssam #define	IFLAGS	(EVENP|ODDP|ECHO)
546615Ssam #else
556615Ssam #define	ISPEED	B4800
566615Ssam #define	IFLAGS	(EVENP|ODDP)
576615Ssam #endif
586615Ssam 
5916190Skarels #define	FASTTIMER	(hz/30)		/* scan rate with silos on */
6016190Skarels 
6113Sbill /*
622479Swnj  * Local variables for the driver
6313Sbill  */
642643Swnj short	dhsar[NDH];			/* software copy of last bar */
652643Swnj short	dhsoftCAR[NDH];
6613Sbill 
672643Swnj struct	tty dh11[NDH*16];
682643Swnj int	ndh11	= NDH*16;
692479Swnj int	dhact;				/* mask of active dh's */
7016190Skarels int	dhsilos;			/* mask of dh's with silo in use */
7116190Skarels int	dhchars[NDH];			/* recent input count */
7216190Skarels int	dhrate[NDH];			/* smoothed input count */
7316190Skarels int	dhhighrate = 100;		/* silo on if dhchars > dhhighrate */
7416190Skarels int	dhlowrate = 75;			/* silo off if dhrate < dhlowrate */
7516190Skarels static short timerstarted;
762479Swnj int	dhstart(), ttrstrt();
7713Sbill 
782479Swnj /*
792479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
802479Swnj  * The UBACVT macro converts a clist space address for unibus uban
812479Swnj  * into an i/o space address for the DMA routine.
822479Swnj  */
8316062Skarels int	dh_ubinfo[NUBA];		/* info about allocated unibus map */
8416062Skarels int	cbase[NUBA];			/* base address in unibus map */
852479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
8613Sbill 
872456Swnj /*
882456Swnj  * Routine for configuration to force a dh to interrupt.
892456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
902456Swnj  */
912468Swnj /*ARGSUSED*/
922605Swnj dhprobe(reg)
932395Swnj 	caddr_t reg;
942395Swnj {
952468Swnj 	register int br, cvec;		/* these are ``value-result'' */
962479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
972395Swnj 
982605Swnj #ifdef lint
992605Swnj 	br = 0; cvec = br; br = cvec;
1007384Sroot 	if (ndh11 == 0) ndh11 = 1;
1014932Swnj 	dhrint(0); dhxint(0);
1022605Swnj #endif
1032696Swnj #ifndef notdef
1042566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1056380Swnj 	DELAY(1000);
1067384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1072566Swnj 	dhaddr->un.dhcsr = 0;
1082566Swnj #else
1092456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1102456Swnj 	DELAY(5);
1112456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1122421Skre 	dhaddr->dhbcr = -1;
1132456Swnj 	dhaddr->dhcar = 0;
1142421Skre 	dhaddr->dhbar = 1;
1152456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1162421Skre 	dhaddr->un.dhcsr = 0;
1172456Swnj 	if (cvec && cvec != 0x200)
1182456Swnj 		cvec -= 4;		/* transmit -> receive */
1192482Swnj #endif
1207408Skre 	return (sizeof (struct dhdevice));
1212395Swnj }
1222395Swnj 
1232456Swnj /*
1242605Swnj  * Routine called to attach a dh.
1252456Swnj  */
1262605Swnj dhattach(ui)
1272974Swnj 	struct uba_device *ui;
1282395Swnj {
1292395Swnj 
1302566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1312395Swnj }
1322395Swnj 
13313Sbill /*
1342479Swnj  * Configuration routine to cause a dm to interrupt.
1352479Swnj  */
1362605Swnj dmprobe(reg)
1372605Swnj 	caddr_t reg;
1382479Swnj {
1392479Swnj 	register int br, vec;			/* value-result */
1402605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1412479Swnj 
1422605Swnj #ifdef lint
1433101Swnj 	br = 0; vec = br; br = vec;
1446185Ssam 	dmintr(0);
1452605Swnj #endif
1462479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1472479Swnj 	DELAY(20);
1482479Swnj 	dmaddr->dmcsr = 0;
1492605Swnj 	return (1);
1502479Swnj }
1512479Swnj 
1522605Swnj /*ARGSUSED*/
1532605Swnj dmattach(ui)
1542974Swnj 	struct uba_device *ui;
1552479Swnj {
1562479Swnj 
1572479Swnj 	/* no local state to set up */
1582479Swnj }
1592479Swnj 
1602479Swnj /*
1612468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1622468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1632468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
16413Sbill  */
16513Sbill /*ARGSUSED*/
16613Sbill dhopen(dev, flag)
1672395Swnj 	dev_t dev;
16813Sbill {
16913Sbill 	register struct tty *tp;
1702395Swnj 	register int unit, dh;
1712479Swnj 	register struct dhdevice *addr;
1722974Swnj 	register struct uba_device *ui;
17313Sbill 	int s;
17413Sbill 
1752395Swnj 	unit = minor(dev);
1762395Swnj 	dh = unit >> 4;
1778566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
1788566Sroot 		return (ENXIO);
1792395Swnj 	tp = &dh11[unit];
1808566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
1818566Sroot 		return (EBUSY);
1822479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
18313Sbill 	tp->t_addr = (caddr_t)addr;
18413Sbill 	tp->t_oproc = dhstart;
1855406Swnj 	tp->t_state |= TS_WOPEN;
1862468Swnj 	/*
1872468Swnj 	 * While setting up state for this uba and this dh,
1882468Swnj 	 * block uba resets which can clear the state.
1892468Swnj 	 */
1902468Swnj 	s = spl5();
1912421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
192717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
1932395Swnj 		dh_ubinfo[ui->ui_ubanum] =
1942421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
1952770Swnj 			512+nclist*sizeof(struct cblock), 0);
1962456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
19713Sbill 	}
19816190Skarels 	if (timerstarted == 0) {
19916190Skarels 		timerstarted++;
20016190Skarels 		timeout(dhtimer, (caddr_t) 0, hz);
20116190Skarels 	}
2022456Swnj 	if ((dhact&(1<<dh)) == 0) {
2032456Swnj 		addr->un.dhcsr |= DH_IE;
2042468Swnj 		dhact |= (1<<dh);
20516190Skarels 		addr->dhsilo = 0;
2062456Swnj 	}
20713Sbill 	splx(s);
2082468Swnj 	/*
2092468Swnj 	 * If this is first open, initialze tty state to default.
2102468Swnj 	 */
2115406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
21213Sbill 		ttychars(tp);
2136615Ssam #ifndef PORTSELECTOR
214168Sbill 		if (tp->t_ispeed == 0) {
2156615Ssam #endif
2166615Ssam 			tp->t_ispeed = ISPEED;
2176615Ssam 			tp->t_ospeed = ISPEED;
2186615Ssam 			tp->t_flags = IFLAGS;
2196615Ssam #ifndef PORTSELECTOR
220168Sbill 		}
2216615Ssam #endif
2222395Swnj 		dhparam(unit);
22313Sbill 	}
2242468Swnj 	/*
2252468Swnj 	 * Wait for carrier, then process line discipline specific open.
2262468Swnj 	 */
22713Sbill 	dmopen(dev);
2288566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
22913Sbill }
23013Sbill 
23113Sbill /*
2322468Swnj  * Close a DH11 line, turning off the DM11.
23313Sbill  */
23413Sbill /*ARGSUSED*/
23513Sbill dhclose(dev, flag)
2362395Swnj 	dev_t dev;
2372395Swnj 	int flag;
23813Sbill {
23913Sbill 	register struct tty *tp;
2402395Swnj 	register unit;
24113Sbill 
2422395Swnj 	unit = minor(dev);
2432395Swnj 	tp = &dh11[unit];
24413Sbill 	(*linesw[tp->t_line].l_close)(tp);
2452479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
2465406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
2472479Swnj 		dmctl(unit, DML_OFF, DMSET);
24813Sbill 	ttyclose(tp);
24913Sbill }
25013Sbill 
2517725Sroot dhread(dev, uio)
2522395Swnj 	dev_t dev;
2537725Sroot 	struct uio *uio;
25413Sbill {
2558490Sroot 	register struct tty *tp = &dh11[minor(dev)];
25613Sbill 
2577725Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
25813Sbill }
25913Sbill 
2607831Sroot dhwrite(dev, uio)
2612395Swnj 	dev_t dev;
2627831Sroot 	struct uio *uio;
26313Sbill {
2648490Sroot 	register struct tty *tp = &dh11[minor(dev)];
26513Sbill 
2668490Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
26713Sbill }
26813Sbill 
26913Sbill /*
27013Sbill  * DH11 receiver interrupt.
27113Sbill  */
2722395Swnj dhrint(dh)
2732395Swnj 	int dh;
27413Sbill {
27513Sbill 	register struct tty *tp;
2762395Swnj 	register c;
2772479Swnj 	register struct dhdevice *addr;
278117Sbill 	register struct tty *tp0;
2792974Swnj 	register struct uba_device *ui;
2802924Swnj 	int overrun = 0;
28113Sbill 
2822395Swnj 	ui = dhinfo[dh];
2832479Swnj 	if (ui == 0 || ui->ui_alive == 0)
2842479Swnj 		return;
2852479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
2862468Swnj 	tp0 = &dh11[dh<<4];
2872468Swnj 	/*
2882468Swnj 	 * Loop fetching characters from the silo for this
2892468Swnj 	 * dh until there are no more in the silo.
2902468Swnj 	 */
2912468Swnj 	while ((c = addr->dhrcr) < 0) {
2922468Swnj 		tp = tp0 + ((c>>8)&0xf);
29316190Skarels 		dhchars[dh]++;
2946615Ssam #ifndef PORTSELECTOR
2955406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
2966615Ssam #else
2976615Ssam 		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
2986615Ssam #endif
29913Sbill 			wakeup((caddr_t)tp);
30013Sbill 			continue;
30113Sbill 		}
3022468Swnj 		if (c & DH_PE)
30313Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
30413Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
30513Sbill 				continue;
3062924Swnj 		if ((c & DH_DO) && overrun == 0) {
30718311Sralph 			log(KERN_RECOV, "dh%d: silo overflow\n", dh);
3082924Swnj 			overrun = 1;
3092924Swnj 		}
3102468Swnj 		if (c & DH_FE)
3112468Swnj 			/*
3122468Swnj 			 * At framing error (break) generate
3132468Swnj 			 * a null (in raw mode, for getty), or a
3142468Swnj 			 * interrupt (in cooked/cbreak mode).
3152468Swnj 			 */
31613Sbill 			if (tp->t_flags&RAW)
3172468Swnj 				c = 0;
31813Sbill 			else
3199549Ssam 				c = tp->t_intrc;
3202730Swnj #if NBK > 0
321139Sbill 		if (tp->t_line == NETLDISC) {
322117Sbill 			c &= 0177;
323168Sbill 			BKINPUT(c, tp);
324117Sbill 		} else
3252730Swnj #endif
3262468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
32713Sbill 	}
32813Sbill }
32913Sbill 
33013Sbill /*
3312468Swnj  * Ioctl for DH11.
33213Sbill  */
33313Sbill /*ARGSUSED*/
3347629Ssam dhioctl(dev, cmd, data, flag)
3357629Ssam 	caddr_t data;
33613Sbill {
33713Sbill 	register struct tty *tp;
3388566Sroot 	register int unit = minor(dev);
3398566Sroot 	int error;
34013Sbill 
3412395Swnj 	tp = &dh11[unit];
3428566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3438566Sroot 	if (error >= 0)
3448566Sroot 		return (error);
3458566Sroot 	error = ttioctl(tp, cmd, data, flag);
3468566Sroot 	if (error >= 0) {
34717561Sbloom 		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
34817561Sbloom 		    cmd == TIOCLBIC || cmd == TIOCLSET)
3492395Swnj 			dhparam(unit);
3508566Sroot 		return (error);
3518566Sroot 	}
3528566Sroot 	switch (cmd) {
3537629Ssam 
354168Sbill 	case TIOCSBRK:
3552479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
356168Sbill 		break;
3577629Ssam 
358168Sbill 	case TIOCCBRK:
3592479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
360168Sbill 		break;
3617629Ssam 
362168Sbill 	case TIOCSDTR:
3632479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
364168Sbill 		break;
3657629Ssam 
366168Sbill 	case TIOCCDTR:
3672479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
368168Sbill 		break;
3697629Ssam 
370168Sbill 	default:
3718566Sroot 		return (ENOTTY);
372168Sbill 	}
3738566Sroot 	return (0);
37413Sbill }
37513Sbill 
37613Sbill /*
37713Sbill  * Set parameters from open or stty into the DH hardware
37813Sbill  * registers.
37913Sbill  */
3802395Swnj dhparam(unit)
3812395Swnj 	register int unit;
38213Sbill {
38313Sbill 	register struct tty *tp;
3842479Swnj 	register struct dhdevice *addr;
3852395Swnj 	register int lpar;
386300Sbill 	int s;
38713Sbill 
3882395Swnj 	tp = &dh11[unit];
3892479Swnj 	addr = (struct dhdevice *)tp->t_addr;
3902468Swnj 	/*
3912468Swnj 	 * Block interrupts so parameters will be set
3922468Swnj 	 * before the line interrupts.
3932468Swnj 	 */
394300Sbill 	s = spl5();
3952468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
39613Sbill 	if ((tp->t_ispeed)==0) {
3975406Swnj 		tp->t_state |= TS_HUPCLS;
3982479Swnj 		dmctl(unit, DML_OFF, DMSET);
39913Sbill 		return;
40013Sbill 	}
4012395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4022468Swnj 	if ((tp->t_ispeed) == B134)
4032395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4049549Ssam 	else if (tp->t_flags & (RAW|LITOUT))
4052395Swnj 		lpar |= BITS8;
40613Sbill 	else
4072395Swnj 		lpar |= BITS7|PENABLE;
40813Sbill 	if ((tp->t_flags&EVENP) == 0)
4092395Swnj 		lpar |= OPAR;
4102468Swnj 	if ((tp->t_ospeed) == B110)
4112395Swnj 		lpar |= TWOSB;
4122395Swnj 	addr->dhlpr = lpar;
413300Sbill 	splx(s);
41413Sbill }
41513Sbill 
41613Sbill /*
41713Sbill  * DH11 transmitter interrupt.
41813Sbill  * Restart each line which used to be active but has
41913Sbill  * terminated transmission since the last interrupt.
42013Sbill  */
4212395Swnj dhxint(dh)
4222395Swnj 	int dh;
42313Sbill {
42413Sbill 	register struct tty *tp;
4252479Swnj 	register struct dhdevice *addr;
42613Sbill 	short ttybit, bar, *sbar;
4272974Swnj 	register struct uba_device *ui;
4282468Swnj 	register int unit;
4292605Swnj 	u_short cntr;
43013Sbill 
4312395Swnj 	ui = dhinfo[dh];
4322479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4332456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4342456Swnj 		addr->un.dhcsr |= DH_CNI;
4352924Swnj 		printf("dh%d: NXM\n", dh);
436105Sbill 	}
4372395Swnj 	sbar = &dhsar[dh];
43813Sbill 	bar = *sbar & ~addr->dhbar;
4392395Swnj 	unit = dh * 16; ttybit = 1;
4402468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4412468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4422468Swnj 		if (bar & ttybit) {
44313Sbill 			*sbar &= ~ttybit;
44413Sbill 			bar &= ~ttybit;
4452395Swnj 			tp = &dh11[unit];
4465406Swnj 			tp->t_state &= ~TS_BUSY;
4475406Swnj 			if (tp->t_state&TS_FLUSH)
4485406Swnj 				tp->t_state &= ~TS_FLUSH;
449113Sbill 			else {
4502456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4512468Swnj 				/*
4522468Swnj 				 * Do arithmetic in a short to make up
4532468Swnj 				 * for lost 16&17 bits.
4542468Swnj 				 */
4552605Swnj 				cntr = addr->dhcar -
4562468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4573101Swnj 				ndflush(&tp->t_outq, (int)cntr);
458113Sbill 			}
459113Sbill 			if (tp->t_line)
46013Sbill 				(*linesw[tp->t_line].l_start)(tp);
461113Sbill 			else
46213Sbill 				dhstart(tp);
46313Sbill 		}
46413Sbill 	}
46513Sbill }
46613Sbill 
46713Sbill /*
46813Sbill  * Start (restart) transmission on the given DH11 line.
46913Sbill  */
47013Sbill dhstart(tp)
4712395Swnj 	register struct tty *tp;
47213Sbill {
4732479Swnj 	register struct dhdevice *addr;
4742468Swnj 	register int car, dh, unit, nch;
4752395Swnj 	int s;
47613Sbill 
4772468Swnj 	unit = minor(tp->t_dev);
4782468Swnj 	dh = unit >> 4;
4792468Swnj 	unit &= 0xf;
4802479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4812468Swnj 
48213Sbill 	/*
4832468Swnj 	 * Must hold interrupts in following code to prevent
4842468Swnj 	 * state of the tp from changing.
48513Sbill 	 */
48613Sbill 	s = spl5();
4872468Swnj 	/*
4882468Swnj 	 * If it's currently active, or delaying, no need to do anything.
4892468Swnj 	 */
4905406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
49113Sbill 		goto out;
4922468Swnj 	/*
4932468Swnj 	 * If there are sleepers, and output has drained below low
4942468Swnj 	 * water mark, wake up the sleepers.
4952468Swnj 	 */
4965406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
4975406Swnj 		if (tp->t_state&TS_ASLEEP) {
4985406Swnj 			tp->t_state &= ~TS_ASLEEP;
4995406Swnj 			wakeup((caddr_t)&tp->t_outq);
5005406Swnj 		}
5015406Swnj 		if (tp->t_wsel) {
5025406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5035406Swnj 			tp->t_wsel = 0;
5045406Swnj 			tp->t_state &= ~TS_WCOLL;
5055406Swnj 		}
50613Sbill 	}
5072468Swnj 	/*
5082468Swnj 	 * Now restart transmission unless the output queue is
5092468Swnj 	 * empty.
5102468Swnj 	 */
51113Sbill 	if (tp->t_outq.c_cc == 0)
51213Sbill 		goto out;
5139549Ssam 	if (tp->t_flags & (RAW|LITOUT))
51413Sbill 		nch = ndqb(&tp->t_outq, 0);
5152395Swnj 	else {
51613Sbill 		nch = ndqb(&tp->t_outq, 0200);
5172468Swnj 		/*
5182468Swnj 		 * If first thing on queue is a delay process it.
5192468Swnj 		 */
52013Sbill 		if (nch == 0) {
52113Sbill 			nch = getc(&tp->t_outq);
5222468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5235406Swnj 			tp->t_state |= TS_TIMEOUT;
52413Sbill 			goto out;
52513Sbill 		}
52613Sbill 	}
5272468Swnj 	/*
5282468Swnj 	 * If characters to transmit, restart transmission.
5292468Swnj 	 */
53013Sbill 	if (nch) {
5312468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5322468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5333586Sroot 		/*
5343586Sroot 		 * The following nonsense with short word
5353586Sroot 		 * is to make sure the dhbar |= word below
5363586Sroot 		 * is done with an interlocking bisw2 instruction.
5373586Sroot 		 */
5383586Sroot 		{ short word = 1 << unit;
5393586Sroot 		dhsar[dh] |= word;
5402468Swnj 		addr->dhcar = car;
54113Sbill 		addr->dhbcr = -nch;
5423586Sroot 		addr->dhbar |= word;
5433586Sroot 		}
5445406Swnj 		tp->t_state |= TS_BUSY;
54513Sbill 	}
5462395Swnj out:
54713Sbill 	splx(s);
54813Sbill }
54913Sbill 
55013Sbill /*
5512468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
55213Sbill  */
55313Sbill /*ARGSUSED*/
55413Sbill dhstop(tp, flag)
5552468Swnj 	register struct tty *tp;
55613Sbill {
5572479Swnj 	register struct dhdevice *addr;
5582395Swnj 	register int unit, s;
55913Sbill 
5602479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5612468Swnj 	/*
5622468Swnj 	 * Block input/output interrupts while messing with state.
5632468Swnj 	 */
5642468Swnj 	s = spl5();
5655406Swnj 	if (tp->t_state & TS_BUSY) {
5662468Swnj 		/*
5672468Swnj 		 * Device is transmitting; stop output
5682468Swnj 		 * by selecting the line and setting the byte
5692468Swnj 		 * count to -1.  We will clean up later
5702468Swnj 		 * by examining the address where the dh stopped.
5712468Swnj 		 */
5722395Swnj 		unit = minor(tp->t_dev);
5732456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
5745406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
5755406Swnj 			tp->t_state |= TS_FLUSH;
576113Sbill 		addr->dhbcr = -1;
577113Sbill 	}
57813Sbill 	splx(s);
57913Sbill }
58013Sbill 
581168Sbill /*
582280Sbill  * Reset state of driver if UBA reset was necessary.
583280Sbill  * Reset the csrl and lpr registers on open lines, and
584280Sbill  * restart transmitters.
585280Sbill  */
5862395Swnj dhreset(uban)
5872468Swnj 	int uban;
588280Sbill {
5892395Swnj 	register int dh, unit;
590280Sbill 	register struct tty *tp;
5912974Swnj 	register struct uba_device *ui;
5922421Skre 	int i;
593280Sbill 
5942421Skre 	if (dh_ubinfo[uban] == 0)
5952421Skre 		return;
5962421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
5972770Swnj 	    512+nclist*sizeof (struct cblock), 0);
5982421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
5992395Swnj 	dh = 0;
6002643Swnj 	for (dh = 0; dh < NDH; dh++) {
6012421Skre 		ui = dhinfo[dh];
6022421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6032421Skre 			continue;
6042924Swnj 		printf(" dh%d", dh);
6052479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
60616190Skarels 		((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
6072421Skre 		unit = dh * 16;
6082421Skre 		for (i = 0; i < 16; i++) {
6092421Skre 			tp = &dh11[unit];
6105406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6112421Skre 				dhparam(unit);
6122479Swnj 				dmctl(unit, DML_ON, DMSET);
6135406Swnj 				tp->t_state &= ~TS_BUSY;
6142421Skre 				dhstart(tp);
6152421Skre 			}
6162421Skre 			unit++;
617300Sbill 		}
618300Sbill 	}
61916190Skarels 	dhsilos = 0;
620280Sbill }
6212395Swnj 
62216190Skarels int dhtransitions, dhslowtimers, dhfasttimers;		/*DEBUG*/
6232468Swnj /*
62416190Skarels  * At software clock interrupt time, check status.
62516190Skarels  * Empty all the dh silos that are in use, and decide whether
62616190Skarels  * to turn any silos off or on.
6272468Swnj  */
6282456Swnj dhtimer()
6292456Swnj {
63016190Skarels 	register int dh, s;
63116190Skarels 	static int timercalls;
6322456Swnj 
63316190Skarels 	if (dhsilos) {
63416190Skarels 		dhfasttimers++;		/*DEBUG*/
63516190Skarels 		timercalls++;
63616190Skarels 		s = spl5();
63716190Skarels 		for (dh = 0; dh < NDH; dh++)
63816190Skarels 			if (dhsilos & (1 << dh))
63916190Skarels 				dhrint(dh);
64016190Skarels 		splx(s);
64116190Skarels 	}
64216190Skarels 	if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
64316190Skarels 		dhslowtimers++;		/*DEBUG*/
64416190Skarels 		timercalls = 0;
64516190Skarels 		for (dh = 0; dh < NDH; dh++) {
64616190Skarels 		    ave(dhrate[dh], dhchars[dh], 8);
64716190Skarels 		    if ((dhchars[dh] > dhhighrate) &&
64816190Skarels 		      ((dhsilos & (1 << dh)) == 0)) {
64916190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
65016190Skarels 			    (dhchars[dh] > 500? 32 : 16);
65116190Skarels 			dhsilos |= (1 << dh);
65216190Skarels 			dhtransitions++;		/*DEBUG*/
65316190Skarels 		    } else if ((dhsilos & (1 << dh)) &&
65416190Skarels 		      (dhrate[dh] < dhlowrate)) {
65516190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
65616190Skarels 			dhsilos &= ~(1 << dh);
65716190Skarels 		    }
65816190Skarels 		    dhchars[dh] = 0;
65916190Skarels 		}
66016190Skarels 	}
66116190Skarels 	timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
6622456Swnj }
6632456Swnj 
6642468Swnj /*
6652479Swnj  * Turn on the line associated with dh dev.
6662468Swnj  */
6672468Swnj dmopen(dev)
6682468Swnj 	dev_t dev;
6692468Swnj {
6702468Swnj 	register struct tty *tp;
6712468Swnj 	register struct dmdevice *addr;
6722974Swnj 	register struct uba_device *ui;
6732468Swnj 	register int unit;
6742468Swnj 	register int dm;
6753792Swnj 	int s;
6762468Swnj 
6772468Swnj 	unit = minor(dev);
6782479Swnj 	dm = unit >> 4;
6792468Swnj 	tp = &dh11[unit];
6802566Swnj 	unit &= 0xf;
68116942Skarels 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
6825406Swnj 		tp->t_state |= TS_CARR_ON;
6832468Swnj 		return;
6842468Swnj 	}
6852468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6863792Swnj 	s = spl5();
6872479Swnj 	addr->dmcsr &= ~DM_SE;
6882479Swnj 	while (addr->dmcsr & DM_BUSY)
6892468Swnj 		;
6902566Swnj 	addr->dmcsr = unit;
6912479Swnj 	addr->dmlstat = DML_ON;
69216942Skarels 	if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit)))
6935406Swnj 		tp->t_state |= TS_CARR_ON;
6943792Swnj 	addr->dmcsr = DM_IE|DM_SE;
6955406Swnj 	while ((tp->t_state&TS_CARR_ON)==0)
6962468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
6973792Swnj 	splx(s);
6982468Swnj }
6992468Swnj 
7002468Swnj /*
7012468Swnj  * Dump control bits into the DM registers.
7022468Swnj  */
7032468Swnj dmctl(dev, bits, how)
7042468Swnj 	dev_t dev;
7052468Swnj 	int bits, how;
7062468Swnj {
7072974Swnj 	register struct uba_device *ui;
7082468Swnj 	register struct dmdevice *addr;
7092468Swnj 	register int unit, s;
7102468Swnj 	int dm;
7112468Swnj 
7122468Swnj 	unit = minor(dev);
7132468Swnj 	dm = unit >> 4;
7142468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7152468Swnj 		return;
7162468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7172468Swnj 	s = spl5();
7182479Swnj 	addr->dmcsr &= ~DM_SE;
7192479Swnj 	while (addr->dmcsr & DM_BUSY)
7202468Swnj 		;
7212468Swnj 	addr->dmcsr = unit & 0xf;
7222468Swnj 	switch(how) {
7232468Swnj 	case DMSET:
7242468Swnj 		addr->dmlstat = bits;
7252468Swnj 		break;
7262468Swnj 	case DMBIS:
7272468Swnj 		addr->dmlstat |= bits;
7282468Swnj 		break;
7292468Swnj 	case DMBIC:
7302468Swnj 		addr->dmlstat &= ~bits;
7312468Swnj 		break;
7322468Swnj 	}
7333792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7342468Swnj 	splx(s);
7352468Swnj }
7362468Swnj 
7372468Swnj /*
7382468Swnj  * DM11 interrupt; deal with carrier transitions.
7392468Swnj  */
7402468Swnj dmintr(dm)
7412468Swnj 	register int dm;
7422468Swnj {
7432974Swnj 	register struct uba_device *ui;
7442468Swnj 	register struct tty *tp;
7452468Swnj 	register struct dmdevice *addr;
74616942Skarels 	int unit;
7472468Swnj 
7482468Swnj 	ui = dminfo[dm];
7492479Swnj 	if (ui == 0)
7502479Swnj 		return;
7512468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7523997Sroot 	if (addr->dmcsr&DM_DONE) {
7533997Sroot 		if (addr->dmcsr&DM_CF) {
75416942Skarels 			unit = addr->dmcsr & 0xf;
75516942Skarels 			tp = &dh11[(dm << 4) + unit];
7563997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7579549Ssam 			if ((tp->t_state&TS_WOPEN) == 0 &&
7589605Ssam 			    (tp->t_flags & MDMBUF)) {
7593997Sroot 				if (addr->dmlstat & DML_CAR) {
7605406Swnj 					tp->t_state &= ~TS_TTSTOP;
7613997Sroot 					ttstart(tp);
7625406Swnj 				} else if ((tp->t_state&TS_TTSTOP) == 0) {
7635406Swnj 					tp->t_state |= TS_TTSTOP;
7643997Sroot 					dhstop(tp, 0);
7653997Sroot 				}
766*21954Skarels 			} else if ((addr->dmlstat & DML_CAR)==0) {
767*21954Skarels 				if ((tp->t_state & TS_CARR_ON) &&
76816942Skarels 				    (tp->t_flags & NOHANG) == 0 &&
76916942Skarels 				    (dhsoftCAR[dm] & (1<<unit)) == 0) {
770*21954Skarels 					if (tp->t_state & TS_ISOPEN) {
771*21954Skarels 						gsignal(tp->t_pgrp, SIGHUP);
772*21954Skarels 						gsignal(tp->t_pgrp, SIGCONT);
773*21954Skarels 						addr->dmlstat = 0;
774*21954Skarels 						ttyflush(tp, FREAD|FWRITE);
775*21954Skarels 					}
776*21954Skarels 					tp->t_state &= ~TS_CARR_ON;
7773997Sroot 				}
7783997Sroot 			} else
7795406Swnj 				tp->t_state |= TS_CARR_ON;
7803997Sroot 		}
7813997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7822468Swnj 	}
7832468Swnj }
7842625Swnj #endif
785