xref: /csrg-svn/sys/vax/uba/dh.c (revision 23320)
1*23320Smckusick /*
2*23320Smckusick  * Copyright (c) 1982 Regents of the University of California.
3*23320Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*23320Smckusick  * specifies the terms and conditions for redistribution.
5*23320Smckusick  *
6*23320Smckusick  *	@(#)dh.c	6.9 (Berkeley) 06/08/85
7*23320Smckusick  */
813Sbill 
91934Swnj #include "dh.h"
102643Swnj #if NDH > 0
1113Sbill /*
122479Swnj  * DH-11/DM-11 driver
1313Sbill  */
149771Ssam #include "../machine/pte.h"
159771Ssam 
162730Swnj #include "bk.h"
1716062Skarels #include "uba.h"
1817122Sbloom #include "param.h"
1917122Sbloom #include "conf.h"
2017122Sbloom #include "dir.h"
2117122Sbloom #include "user.h"
2217122Sbloom #include "proc.h"
2317122Sbloom #include "ioctl.h"
2417122Sbloom #include "tty.h"
2517122Sbloom #include "map.h"
2617122Sbloom #include "buf.h"
2717122Sbloom #include "vm.h"
2817122Sbloom #include "kernel.h"
2918311Sralph #include "syslog.h"
308472Sroot 
3117122Sbloom #include "ubareg.h"
3217122Sbloom #include "ubavar.h"
3317122Sbloom #include "dhreg.h"
3417122Sbloom #include "dmreg.h"
358472Sroot 
3617122Sbloom #include "bkmac.h"
3717122Sbloom #include "clist.h"
3817122Sbloom #include "file.h"
3917122Sbloom #include "uio.h"
4013Sbill 
412468Swnj /*
422479Swnj  * Definition of the driver for the auto-configuration program.
432479Swnj  * There is one definition for the dh and one for the dm.
442468Swnj  */
4516190Skarels int	dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
462974Swnj struct	uba_device *dhinfo[NDH];
472395Swnj u_short	dhstd[] = { 0 };
482395Swnj struct	uba_driver dhdriver =
492605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
502395Swnj 
512605Swnj int	dmprobe(), dmattach(), dmintr();
522974Swnj struct	uba_device *dminfo[NDH];
532479Swnj u_short	dmstd[] = { 0 };
542479Swnj struct	uba_driver dmdriver =
552605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
5613Sbill 
576615Ssam #ifndef	PORTSELECTOR
586615Ssam #define	ISPEED	B300
596615Ssam #define	IFLAGS	(EVENP|ODDP|ECHO)
606615Ssam #else
616615Ssam #define	ISPEED	B4800
626615Ssam #define	IFLAGS	(EVENP|ODDP)
636615Ssam #endif
646615Ssam 
6516190Skarels #define	FASTTIMER	(hz/30)		/* scan rate with silos on */
6616190Skarels 
6713Sbill /*
682479Swnj  * Local variables for the driver
6913Sbill  */
702643Swnj short	dhsar[NDH];			/* software copy of last bar */
712643Swnj short	dhsoftCAR[NDH];
7213Sbill 
732643Swnj struct	tty dh11[NDH*16];
742643Swnj int	ndh11	= NDH*16;
752479Swnj int	dhact;				/* mask of active dh's */
7616190Skarels int	dhsilos;			/* mask of dh's with silo in use */
7716190Skarels int	dhchars[NDH];			/* recent input count */
7816190Skarels int	dhrate[NDH];			/* smoothed input count */
7916190Skarels int	dhhighrate = 100;		/* silo on if dhchars > dhhighrate */
8016190Skarels int	dhlowrate = 75;			/* silo off if dhrate < dhlowrate */
8116190Skarels static short timerstarted;
822479Swnj int	dhstart(), ttrstrt();
8313Sbill 
842479Swnj /*
852479Swnj  * The clist space is mapped by the driver onto each UNIBUS.
862479Swnj  * The UBACVT macro converts a clist space address for unibus uban
872479Swnj  * into an i/o space address for the DMA routine.
882479Swnj  */
8916062Skarels int	dh_ubinfo[NUBA];		/* info about allocated unibus map */
9016062Skarels int	cbase[NUBA];			/* base address in unibus map */
912479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
9213Sbill 
932456Swnj /*
942456Swnj  * Routine for configuration to force a dh to interrupt.
952456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
962456Swnj  */
972468Swnj /*ARGSUSED*/
982605Swnj dhprobe(reg)
992395Swnj 	caddr_t reg;
1002395Swnj {
1012468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1022479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1032395Swnj 
1042605Swnj #ifdef lint
1052605Swnj 	br = 0; cvec = br; br = cvec;
1067384Sroot 	if (ndh11 == 0) ndh11 = 1;
1074932Swnj 	dhrint(0); dhxint(0);
1082605Swnj #endif
1092696Swnj #ifndef notdef
1102566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1116380Swnj 	DELAY(1000);
1127384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1132566Swnj 	dhaddr->un.dhcsr = 0;
1142566Swnj #else
1152456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1162456Swnj 	DELAY(5);
1172456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1182421Skre 	dhaddr->dhbcr = -1;
1192456Swnj 	dhaddr->dhcar = 0;
1202421Skre 	dhaddr->dhbar = 1;
1212456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1222421Skre 	dhaddr->un.dhcsr = 0;
1232456Swnj 	if (cvec && cvec != 0x200)
1242456Swnj 		cvec -= 4;		/* transmit -> receive */
1252482Swnj #endif
1267408Skre 	return (sizeof (struct dhdevice));
1272395Swnj }
1282395Swnj 
1292456Swnj /*
1302605Swnj  * Routine called to attach a dh.
1312456Swnj  */
1322605Swnj dhattach(ui)
1332974Swnj 	struct uba_device *ui;
1342395Swnj {
1352395Swnj 
1362566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
1372395Swnj }
1382395Swnj 
13913Sbill /*
1402479Swnj  * Configuration routine to cause a dm to interrupt.
1412479Swnj  */
1422605Swnj dmprobe(reg)
1432605Swnj 	caddr_t reg;
1442479Swnj {
1452479Swnj 	register int br, vec;			/* value-result */
1462605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1472479Swnj 
1482605Swnj #ifdef lint
1493101Swnj 	br = 0; vec = br; br = vec;
1506185Ssam 	dmintr(0);
1512605Swnj #endif
1522479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1532479Swnj 	DELAY(20);
1542479Swnj 	dmaddr->dmcsr = 0;
1552605Swnj 	return (1);
1562479Swnj }
1572479Swnj 
1582605Swnj /*ARGSUSED*/
1592605Swnj dmattach(ui)
1602974Swnj 	struct uba_device *ui;
1612479Swnj {
1622479Swnj 
1632479Swnj 	/* no local state to set up */
1642479Swnj }
1652479Swnj 
1662479Swnj /*
1672468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1682468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1692468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
17013Sbill  */
17113Sbill /*ARGSUSED*/
17213Sbill dhopen(dev, flag)
1732395Swnj 	dev_t dev;
17413Sbill {
17513Sbill 	register struct tty *tp;
1762395Swnj 	register int unit, dh;
1772479Swnj 	register struct dhdevice *addr;
1782974Swnj 	register struct uba_device *ui;
17913Sbill 	int s;
18013Sbill 
1812395Swnj 	unit = minor(dev);
1822395Swnj 	dh = unit >> 4;
1838566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
1848566Sroot 		return (ENXIO);
1852395Swnj 	tp = &dh11[unit];
1868566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
1878566Sroot 		return (EBUSY);
1882479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
18913Sbill 	tp->t_addr = (caddr_t)addr;
19013Sbill 	tp->t_oproc = dhstart;
1915406Swnj 	tp->t_state |= TS_WOPEN;
1922468Swnj 	/*
1932468Swnj 	 * While setting up state for this uba and this dh,
1942468Swnj 	 * block uba resets which can clear the state.
1952468Swnj 	 */
1962468Swnj 	s = spl5();
1972421Skre 	if (dh_ubinfo[ui->ui_ubanum] == 0) {
198717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
1992395Swnj 		dh_ubinfo[ui->ui_ubanum] =
2002421Skre 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2012770Swnj 			512+nclist*sizeof(struct cblock), 0);
2022456Swnj 		cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff;
20313Sbill 	}
20416190Skarels 	if (timerstarted == 0) {
20516190Skarels 		timerstarted++;
20616190Skarels 		timeout(dhtimer, (caddr_t) 0, hz);
20716190Skarels 	}
2082456Swnj 	if ((dhact&(1<<dh)) == 0) {
2092456Swnj 		addr->un.dhcsr |= DH_IE;
2102468Swnj 		dhact |= (1<<dh);
21116190Skarels 		addr->dhsilo = 0;
2122456Swnj 	}
21313Sbill 	splx(s);
2142468Swnj 	/*
2152468Swnj 	 * If this is first open, initialze tty state to default.
2162468Swnj 	 */
2175406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
21813Sbill 		ttychars(tp);
2196615Ssam #ifndef PORTSELECTOR
220168Sbill 		if (tp->t_ispeed == 0) {
2216615Ssam #endif
2226615Ssam 			tp->t_ispeed = ISPEED;
2236615Ssam 			tp->t_ospeed = ISPEED;
2246615Ssam 			tp->t_flags = IFLAGS;
2256615Ssam #ifndef PORTSELECTOR
226168Sbill 		}
2276615Ssam #endif
2282395Swnj 		dhparam(unit);
22913Sbill 	}
2302468Swnj 	/*
2312468Swnj 	 * Wait for carrier, then process line discipline specific open.
2322468Swnj 	 */
23313Sbill 	dmopen(dev);
2348566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
23513Sbill }
23613Sbill 
23713Sbill /*
2382468Swnj  * Close a DH11 line, turning off the DM11.
23913Sbill  */
24013Sbill /*ARGSUSED*/
24113Sbill dhclose(dev, flag)
2422395Swnj 	dev_t dev;
2432395Swnj 	int flag;
24413Sbill {
24513Sbill 	register struct tty *tp;
2462395Swnj 	register unit;
24713Sbill 
2482395Swnj 	unit = minor(dev);
2492395Swnj 	tp = &dh11[unit];
25013Sbill 	(*linesw[tp->t_line].l_close)(tp);
2512479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
2525406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
2532479Swnj 		dmctl(unit, DML_OFF, DMSET);
25413Sbill 	ttyclose(tp);
25513Sbill }
25613Sbill 
2577725Sroot dhread(dev, uio)
2582395Swnj 	dev_t dev;
2597725Sroot 	struct uio *uio;
26013Sbill {
2618490Sroot 	register struct tty *tp = &dh11[minor(dev)];
26213Sbill 
2637725Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
26413Sbill }
26513Sbill 
2667831Sroot dhwrite(dev, uio)
2672395Swnj 	dev_t dev;
2687831Sroot 	struct uio *uio;
26913Sbill {
2708490Sroot 	register struct tty *tp = &dh11[minor(dev)];
27113Sbill 
2728490Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
27313Sbill }
27413Sbill 
27513Sbill /*
27613Sbill  * DH11 receiver interrupt.
27713Sbill  */
2782395Swnj dhrint(dh)
2792395Swnj 	int dh;
28013Sbill {
28113Sbill 	register struct tty *tp;
2822395Swnj 	register c;
2832479Swnj 	register struct dhdevice *addr;
284117Sbill 	register struct tty *tp0;
2852974Swnj 	register struct uba_device *ui;
2862924Swnj 	int overrun = 0;
28713Sbill 
2882395Swnj 	ui = dhinfo[dh];
2892479Swnj 	if (ui == 0 || ui->ui_alive == 0)
2902479Swnj 		return;
2912479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
2922468Swnj 	tp0 = &dh11[dh<<4];
2932468Swnj 	/*
2942468Swnj 	 * Loop fetching characters from the silo for this
2952468Swnj 	 * dh until there are no more in the silo.
2962468Swnj 	 */
2972468Swnj 	while ((c = addr->dhrcr) < 0) {
2982468Swnj 		tp = tp0 + ((c>>8)&0xf);
29916190Skarels 		dhchars[dh]++;
3006615Ssam #ifndef PORTSELECTOR
3015406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
3026615Ssam #else
3036615Ssam 		if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) {
3046615Ssam #endif
30513Sbill 			wakeup((caddr_t)tp);
30613Sbill 			continue;
30713Sbill 		}
3082468Swnj 		if (c & DH_PE)
30913Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
31013Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
31113Sbill 				continue;
3122924Swnj 		if ((c & DH_DO) && overrun == 0) {
31318311Sralph 			log(KERN_RECOV, "dh%d: silo overflow\n", dh);
3142924Swnj 			overrun = 1;
3152924Swnj 		}
3162468Swnj 		if (c & DH_FE)
3172468Swnj 			/*
3182468Swnj 			 * At framing error (break) generate
3192468Swnj 			 * a null (in raw mode, for getty), or a
3202468Swnj 			 * interrupt (in cooked/cbreak mode).
3212468Swnj 			 */
32213Sbill 			if (tp->t_flags&RAW)
3232468Swnj 				c = 0;
32413Sbill 			else
3259549Ssam 				c = tp->t_intrc;
3262730Swnj #if NBK > 0
327139Sbill 		if (tp->t_line == NETLDISC) {
328117Sbill 			c &= 0177;
329168Sbill 			BKINPUT(c, tp);
330117Sbill 		} else
3312730Swnj #endif
3322468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
33313Sbill 	}
33413Sbill }
33513Sbill 
33613Sbill /*
3372468Swnj  * Ioctl for DH11.
33813Sbill  */
33913Sbill /*ARGSUSED*/
3407629Ssam dhioctl(dev, cmd, data, flag)
3417629Ssam 	caddr_t data;
34213Sbill {
34313Sbill 	register struct tty *tp;
3448566Sroot 	register int unit = minor(dev);
3458566Sroot 	int error;
34613Sbill 
3472395Swnj 	tp = &dh11[unit];
3488566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3498566Sroot 	if (error >= 0)
3508566Sroot 		return (error);
3518566Sroot 	error = ttioctl(tp, cmd, data, flag);
3528566Sroot 	if (error >= 0) {
35317561Sbloom 		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
35417561Sbloom 		    cmd == TIOCLBIC || cmd == TIOCLSET)
3552395Swnj 			dhparam(unit);
3568566Sroot 		return (error);
3578566Sroot 	}
3588566Sroot 	switch (cmd) {
3597629Ssam 
360168Sbill 	case TIOCSBRK:
3612479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
362168Sbill 		break;
3637629Ssam 
364168Sbill 	case TIOCCBRK:
3652479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
366168Sbill 		break;
3677629Ssam 
368168Sbill 	case TIOCSDTR:
3692479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
370168Sbill 		break;
3717629Ssam 
372168Sbill 	case TIOCCDTR:
3732479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
374168Sbill 		break;
3757629Ssam 
376168Sbill 	default:
3778566Sroot 		return (ENOTTY);
378168Sbill 	}
3798566Sroot 	return (0);
38013Sbill }
38113Sbill 
38213Sbill /*
38313Sbill  * Set parameters from open or stty into the DH hardware
38413Sbill  * registers.
38513Sbill  */
3862395Swnj dhparam(unit)
3872395Swnj 	register int unit;
38813Sbill {
38913Sbill 	register struct tty *tp;
3902479Swnj 	register struct dhdevice *addr;
3912395Swnj 	register int lpar;
392300Sbill 	int s;
39313Sbill 
3942395Swnj 	tp = &dh11[unit];
3952479Swnj 	addr = (struct dhdevice *)tp->t_addr;
3962468Swnj 	/*
3972468Swnj 	 * Block interrupts so parameters will be set
3982468Swnj 	 * before the line interrupts.
3992468Swnj 	 */
400300Sbill 	s = spl5();
4012468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
40213Sbill 	if ((tp->t_ispeed)==0) {
4035406Swnj 		tp->t_state |= TS_HUPCLS;
4042479Swnj 		dmctl(unit, DML_OFF, DMSET);
40513Sbill 		return;
40613Sbill 	}
4072395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4082468Swnj 	if ((tp->t_ispeed) == B134)
4092395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
4109549Ssam 	else if (tp->t_flags & (RAW|LITOUT))
4112395Swnj 		lpar |= BITS8;
41213Sbill 	else
4132395Swnj 		lpar |= BITS7|PENABLE;
41413Sbill 	if ((tp->t_flags&EVENP) == 0)
4152395Swnj 		lpar |= OPAR;
4162468Swnj 	if ((tp->t_ospeed) == B110)
4172395Swnj 		lpar |= TWOSB;
4182395Swnj 	addr->dhlpr = lpar;
419300Sbill 	splx(s);
42013Sbill }
42113Sbill 
42213Sbill /*
42313Sbill  * DH11 transmitter interrupt.
42413Sbill  * Restart each line which used to be active but has
42513Sbill  * terminated transmission since the last interrupt.
42613Sbill  */
4272395Swnj dhxint(dh)
4282395Swnj 	int dh;
42913Sbill {
43013Sbill 	register struct tty *tp;
4312479Swnj 	register struct dhdevice *addr;
43213Sbill 	short ttybit, bar, *sbar;
4332974Swnj 	register struct uba_device *ui;
4342468Swnj 	register int unit;
4352605Swnj 	u_short cntr;
43613Sbill 
4372395Swnj 	ui = dhinfo[dh];
4382479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4392456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4402456Swnj 		addr->un.dhcsr |= DH_CNI;
4412924Swnj 		printf("dh%d: NXM\n", dh);
442105Sbill 	}
4432395Swnj 	sbar = &dhsar[dh];
44413Sbill 	bar = *sbar & ~addr->dhbar;
4452395Swnj 	unit = dh * 16; ttybit = 1;
4462468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4472468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4482468Swnj 		if (bar & ttybit) {
44913Sbill 			*sbar &= ~ttybit;
45013Sbill 			bar &= ~ttybit;
4512395Swnj 			tp = &dh11[unit];
4525406Swnj 			tp->t_state &= ~TS_BUSY;
4535406Swnj 			if (tp->t_state&TS_FLUSH)
4545406Swnj 				tp->t_state &= ~TS_FLUSH;
455113Sbill 			else {
4562456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4572468Swnj 				/*
4582468Swnj 				 * Do arithmetic in a short to make up
4592468Swnj 				 * for lost 16&17 bits.
4602468Swnj 				 */
4612605Swnj 				cntr = addr->dhcar -
4622468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4633101Swnj 				ndflush(&tp->t_outq, (int)cntr);
464113Sbill 			}
465113Sbill 			if (tp->t_line)
46613Sbill 				(*linesw[tp->t_line].l_start)(tp);
467113Sbill 			else
46813Sbill 				dhstart(tp);
46913Sbill 		}
47013Sbill 	}
47113Sbill }
47213Sbill 
47313Sbill /*
47413Sbill  * Start (restart) transmission on the given DH11 line.
47513Sbill  */
47613Sbill dhstart(tp)
4772395Swnj 	register struct tty *tp;
47813Sbill {
4792479Swnj 	register struct dhdevice *addr;
4802468Swnj 	register int car, dh, unit, nch;
4812395Swnj 	int s;
48213Sbill 
4832468Swnj 	unit = minor(tp->t_dev);
4842468Swnj 	dh = unit >> 4;
4852468Swnj 	unit &= 0xf;
4862479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4872468Swnj 
48813Sbill 	/*
4892468Swnj 	 * Must hold interrupts in following code to prevent
4902468Swnj 	 * state of the tp from changing.
49113Sbill 	 */
49213Sbill 	s = spl5();
4932468Swnj 	/*
4942468Swnj 	 * If it's currently active, or delaying, no need to do anything.
4952468Swnj 	 */
4965406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
49713Sbill 		goto out;
4982468Swnj 	/*
4992468Swnj 	 * If there are sleepers, and output has drained below low
5002468Swnj 	 * water mark, wake up the sleepers.
5012468Swnj 	 */
5025406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
5035406Swnj 		if (tp->t_state&TS_ASLEEP) {
5045406Swnj 			tp->t_state &= ~TS_ASLEEP;
5055406Swnj 			wakeup((caddr_t)&tp->t_outq);
5065406Swnj 		}
5075406Swnj 		if (tp->t_wsel) {
5085406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5095406Swnj 			tp->t_wsel = 0;
5105406Swnj 			tp->t_state &= ~TS_WCOLL;
5115406Swnj 		}
51213Sbill 	}
5132468Swnj 	/*
5142468Swnj 	 * Now restart transmission unless the output queue is
5152468Swnj 	 * empty.
5162468Swnj 	 */
51713Sbill 	if (tp->t_outq.c_cc == 0)
51813Sbill 		goto out;
5199549Ssam 	if (tp->t_flags & (RAW|LITOUT))
52013Sbill 		nch = ndqb(&tp->t_outq, 0);
5212395Swnj 	else {
52213Sbill 		nch = ndqb(&tp->t_outq, 0200);
5232468Swnj 		/*
5242468Swnj 		 * If first thing on queue is a delay process it.
5252468Swnj 		 */
52613Sbill 		if (nch == 0) {
52713Sbill 			nch = getc(&tp->t_outq);
5282468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5295406Swnj 			tp->t_state |= TS_TIMEOUT;
53013Sbill 			goto out;
53113Sbill 		}
53213Sbill 	}
5332468Swnj 	/*
5342468Swnj 	 * If characters to transmit, restart transmission.
5352468Swnj 	 */
53613Sbill 	if (nch) {
5372468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5382468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5393586Sroot 		/*
5403586Sroot 		 * The following nonsense with short word
5413586Sroot 		 * is to make sure the dhbar |= word below
5423586Sroot 		 * is done with an interlocking bisw2 instruction.
5433586Sroot 		 */
5443586Sroot 		{ short word = 1 << unit;
5453586Sroot 		dhsar[dh] |= word;
5462468Swnj 		addr->dhcar = car;
54713Sbill 		addr->dhbcr = -nch;
5483586Sroot 		addr->dhbar |= word;
5493586Sroot 		}
5505406Swnj 		tp->t_state |= TS_BUSY;
55113Sbill 	}
5522395Swnj out:
55313Sbill 	splx(s);
55413Sbill }
55513Sbill 
55613Sbill /*
5572468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
55813Sbill  */
55913Sbill /*ARGSUSED*/
56013Sbill dhstop(tp, flag)
5612468Swnj 	register struct tty *tp;
56213Sbill {
5632479Swnj 	register struct dhdevice *addr;
5642395Swnj 	register int unit, s;
56513Sbill 
5662479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5672468Swnj 	/*
5682468Swnj 	 * Block input/output interrupts while messing with state.
5692468Swnj 	 */
5702468Swnj 	s = spl5();
5715406Swnj 	if (tp->t_state & TS_BUSY) {
5722468Swnj 		/*
5732468Swnj 		 * Device is transmitting; stop output
5742468Swnj 		 * by selecting the line and setting the byte
5752468Swnj 		 * count to -1.  We will clean up later
5762468Swnj 		 * by examining the address where the dh stopped.
5772468Swnj 		 */
5782395Swnj 		unit = minor(tp->t_dev);
5792456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
5805406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
5815406Swnj 			tp->t_state |= TS_FLUSH;
582113Sbill 		addr->dhbcr = -1;
583113Sbill 	}
58413Sbill 	splx(s);
58513Sbill }
58613Sbill 
587168Sbill /*
588280Sbill  * Reset state of driver if UBA reset was necessary.
589280Sbill  * Reset the csrl and lpr registers on open lines, and
590280Sbill  * restart transmitters.
591280Sbill  */
5922395Swnj dhreset(uban)
5932468Swnj 	int uban;
594280Sbill {
5952395Swnj 	register int dh, unit;
596280Sbill 	register struct tty *tp;
5972974Swnj 	register struct uba_device *ui;
5982421Skre 	int i;
599280Sbill 
6002421Skre 	if (dh_ubinfo[uban] == 0)
6012421Skre 		return;
6022421Skre 	dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6032770Swnj 	    512+nclist*sizeof (struct cblock), 0);
6042421Skre 	cbase[uban] = dh_ubinfo[uban]&0x3ffff;
6052395Swnj 	dh = 0;
6062643Swnj 	for (dh = 0; dh < NDH; dh++) {
6072421Skre 		ui = dhinfo[dh];
6082421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6092421Skre 			continue;
6102924Swnj 		printf(" dh%d", dh);
6112479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
61216190Skarels 		((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
6132421Skre 		unit = dh * 16;
6142421Skre 		for (i = 0; i < 16; i++) {
6152421Skre 			tp = &dh11[unit];
6165406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6172421Skre 				dhparam(unit);
6182479Swnj 				dmctl(unit, DML_ON, DMSET);
6195406Swnj 				tp->t_state &= ~TS_BUSY;
6202421Skre 				dhstart(tp);
6212421Skre 			}
6222421Skre 			unit++;
623300Sbill 		}
624300Sbill 	}
62516190Skarels 	dhsilos = 0;
626280Sbill }
6272395Swnj 
62816190Skarels int dhtransitions, dhslowtimers, dhfasttimers;		/*DEBUG*/
6292468Swnj /*
63016190Skarels  * At software clock interrupt time, check status.
63116190Skarels  * Empty all the dh silos that are in use, and decide whether
63216190Skarels  * to turn any silos off or on.
6332468Swnj  */
6342456Swnj dhtimer()
6352456Swnj {
63616190Skarels 	register int dh, s;
63716190Skarels 	static int timercalls;
6382456Swnj 
63916190Skarels 	if (dhsilos) {
64016190Skarels 		dhfasttimers++;		/*DEBUG*/
64116190Skarels 		timercalls++;
64216190Skarels 		s = spl5();
64316190Skarels 		for (dh = 0; dh < NDH; dh++)
64416190Skarels 			if (dhsilos & (1 << dh))
64516190Skarels 				dhrint(dh);
64616190Skarels 		splx(s);
64716190Skarels 	}
64816190Skarels 	if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
64916190Skarels 		dhslowtimers++;		/*DEBUG*/
65016190Skarels 		timercalls = 0;
65116190Skarels 		for (dh = 0; dh < NDH; dh++) {
65216190Skarels 		    ave(dhrate[dh], dhchars[dh], 8);
65316190Skarels 		    if ((dhchars[dh] > dhhighrate) &&
65416190Skarels 		      ((dhsilos & (1 << dh)) == 0)) {
65516190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
65616190Skarels 			    (dhchars[dh] > 500? 32 : 16);
65716190Skarels 			dhsilos |= (1 << dh);
65816190Skarels 			dhtransitions++;		/*DEBUG*/
65916190Skarels 		    } else if ((dhsilos & (1 << dh)) &&
66016190Skarels 		      (dhrate[dh] < dhlowrate)) {
66116190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
66216190Skarels 			dhsilos &= ~(1 << dh);
66316190Skarels 		    }
66416190Skarels 		    dhchars[dh] = 0;
66516190Skarels 		}
66616190Skarels 	}
66716190Skarels 	timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
6682456Swnj }
6692456Swnj 
6702468Swnj /*
6712479Swnj  * Turn on the line associated with dh dev.
6722468Swnj  */
6732468Swnj dmopen(dev)
6742468Swnj 	dev_t dev;
6752468Swnj {
6762468Swnj 	register struct tty *tp;
6772468Swnj 	register struct dmdevice *addr;
6782974Swnj 	register struct uba_device *ui;
6792468Swnj 	register int unit;
6802468Swnj 	register int dm;
6813792Swnj 	int s;
6822468Swnj 
6832468Swnj 	unit = minor(dev);
6842479Swnj 	dm = unit >> 4;
6852468Swnj 	tp = &dh11[unit];
6862566Swnj 	unit &= 0xf;
68716942Skarels 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
6885406Swnj 		tp->t_state |= TS_CARR_ON;
6892468Swnj 		return;
6902468Swnj 	}
6912468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
6923792Swnj 	s = spl5();
6932479Swnj 	addr->dmcsr &= ~DM_SE;
6942479Swnj 	while (addr->dmcsr & DM_BUSY)
6952468Swnj 		;
6962566Swnj 	addr->dmcsr = unit;
6972479Swnj 	addr->dmlstat = DML_ON;
69816942Skarels 	if ((addr->dmlstat&DML_CAR) || (dhsoftCAR[dm]&(1<<unit)))
6995406Swnj 		tp->t_state |= TS_CARR_ON;
7003792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7015406Swnj 	while ((tp->t_state&TS_CARR_ON)==0)
7022468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
7033792Swnj 	splx(s);
7042468Swnj }
7052468Swnj 
7062468Swnj /*
7072468Swnj  * Dump control bits into the DM registers.
7082468Swnj  */
7092468Swnj dmctl(dev, bits, how)
7102468Swnj 	dev_t dev;
7112468Swnj 	int bits, how;
7122468Swnj {
7132974Swnj 	register struct uba_device *ui;
7142468Swnj 	register struct dmdevice *addr;
7152468Swnj 	register int unit, s;
7162468Swnj 	int dm;
7172468Swnj 
7182468Swnj 	unit = minor(dev);
7192468Swnj 	dm = unit >> 4;
7202468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7212468Swnj 		return;
7222468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7232468Swnj 	s = spl5();
7242479Swnj 	addr->dmcsr &= ~DM_SE;
7252479Swnj 	while (addr->dmcsr & DM_BUSY)
7262468Swnj 		;
7272468Swnj 	addr->dmcsr = unit & 0xf;
7282468Swnj 	switch(how) {
7292468Swnj 	case DMSET:
7302468Swnj 		addr->dmlstat = bits;
7312468Swnj 		break;
7322468Swnj 	case DMBIS:
7332468Swnj 		addr->dmlstat |= bits;
7342468Swnj 		break;
7352468Swnj 	case DMBIC:
7362468Swnj 		addr->dmlstat &= ~bits;
7372468Swnj 		break;
7382468Swnj 	}
7393792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7402468Swnj 	splx(s);
7412468Swnj }
7422468Swnj 
7432468Swnj /*
7442468Swnj  * DM11 interrupt; deal with carrier transitions.
7452468Swnj  */
7462468Swnj dmintr(dm)
7472468Swnj 	register int dm;
7482468Swnj {
7492974Swnj 	register struct uba_device *ui;
7502468Swnj 	register struct tty *tp;
7512468Swnj 	register struct dmdevice *addr;
75216942Skarels 	int unit;
7532468Swnj 
7542468Swnj 	ui = dminfo[dm];
7552479Swnj 	if (ui == 0)
7562479Swnj 		return;
7572468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7583997Sroot 	if (addr->dmcsr&DM_DONE) {
7593997Sroot 		if (addr->dmcsr&DM_CF) {
76016942Skarels 			unit = addr->dmcsr & 0xf;
76116942Skarels 			tp = &dh11[(dm << 4) + unit];
7623997Sroot 			wakeup((caddr_t)&tp->t_rawq);
7639549Ssam 			if ((tp->t_state&TS_WOPEN) == 0 &&
7649605Ssam 			    (tp->t_flags & MDMBUF)) {
7653997Sroot 				if (addr->dmlstat & DML_CAR) {
7665406Swnj 					tp->t_state &= ~TS_TTSTOP;
7673997Sroot 					ttstart(tp);
7685406Swnj 				} else if ((tp->t_state&TS_TTSTOP) == 0) {
7695406Swnj 					tp->t_state |= TS_TTSTOP;
7703997Sroot 					dhstop(tp, 0);
7713997Sroot 				}
77221954Skarels 			} else if ((addr->dmlstat & DML_CAR)==0) {
77321954Skarels 				if ((tp->t_state & TS_CARR_ON) &&
77416942Skarels 				    (tp->t_flags & NOHANG) == 0 &&
77516942Skarels 				    (dhsoftCAR[dm] & (1<<unit)) == 0) {
77621954Skarels 					if (tp->t_state & TS_ISOPEN) {
77721954Skarels 						gsignal(tp->t_pgrp, SIGHUP);
77821954Skarels 						gsignal(tp->t_pgrp, SIGCONT);
77921954Skarels 						addr->dmlstat = 0;
78021954Skarels 						ttyflush(tp, FREAD|FWRITE);
78121954Skarels 					}
78221954Skarels 					tp->t_state &= ~TS_CARR_ON;
7833997Sroot 				}
7843997Sroot 			} else
7855406Swnj 				tp->t_state |= TS_CARR_ON;
7863997Sroot 		}
7873997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7882468Swnj 	}
7892468Swnj }
7902625Swnj #endif
791