xref: /csrg-svn/sys/vax/uba/dh.c (revision 30349)
123320Smckusick /*
229209Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323320Smckusick  * All rights reserved.  The Berkeley software License Agreement
423320Smckusick  * specifies the terms and conditions for redistribution.
523320Smckusick  *
6*30349Skarels  *	@(#)dh.c	7.4 (Berkeley) 12/30/86
723320Smckusick  */
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
5825394Skarels #define	ISPEED	B9600
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 /*
8530322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
8630322Skarels  * The identity of the board which allocated resources is recorded,
8730322Skarels  * so the process may be repeated after UNIBUS resets.
882479Swnj  * The UBACVT macro converts a clist space address for unibus uban
892479Swnj  * into an i/o space address for the DMA routine.
902479Swnj  */
9130322Skarels int	dh_uballoc[NUBA];	/* which dh (if any) allocated unibus map */
9230322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
932479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
9413Sbill 
952456Swnj /*
962456Swnj  * Routine for configuration to force a dh to interrupt.
972456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
982456Swnj  */
992468Swnj /*ARGSUSED*/
1002605Swnj dhprobe(reg)
101*30349Skarels p
1022395Swnj 	caddr_t reg;
1032395Swnj {
1042468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1052479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1062395Swnj 
1072605Swnj #ifdef lint
1082605Swnj 	br = 0; cvec = br; br = cvec;
1097384Sroot 	if (ndh11 == 0) ndh11 = 1;
1104932Swnj 	dhrint(0); dhxint(0);
1112605Swnj #endif
1122696Swnj #ifndef notdef
1132566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1146380Swnj 	DELAY(1000);
1157384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1162566Swnj 	dhaddr->un.dhcsr = 0;
1172566Swnj #else
1182456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1192456Swnj 	DELAY(5);
1202456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1212421Skre 	dhaddr->dhbcr = -1;
1222456Swnj 	dhaddr->dhcar = 0;
1232421Skre 	dhaddr->dhbar = 1;
1242456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1252421Skre 	dhaddr->un.dhcsr = 0;
1262456Swnj 	if (cvec && cvec != 0x200)
1272456Swnj 		cvec -= 4;		/* transmit -> receive */
1282482Swnj #endif
1297408Skre 	return (sizeof (struct dhdevice));
1302395Swnj }
1312395Swnj 
1322456Swnj /*
1332605Swnj  * Routine called to attach a dh.
1342456Swnj  */
1352605Swnj dhattach(ui)
1362974Swnj 	struct uba_device *ui;
1372395Swnj {
1382395Swnj 
1392566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
14026219Skarels 	cbase[ui->ui_ubanum] = -1;
14130322Skarels 	dh_uballoc[ui->ui_unit] = -1;
1422395Swnj }
1432395Swnj 
14413Sbill /*
1452479Swnj  * Configuration routine to cause a dm to interrupt.
1462479Swnj  */
1472605Swnj dmprobe(reg)
1482605Swnj 	caddr_t reg;
1492479Swnj {
1502479Swnj 	register int br, vec;			/* value-result */
1512605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1522479Swnj 
1532605Swnj #ifdef lint
1543101Swnj 	br = 0; vec = br; br = vec;
1556185Ssam 	dmintr(0);
1562605Swnj #endif
1572479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1582479Swnj 	DELAY(20);
1592479Swnj 	dmaddr->dmcsr = 0;
1602605Swnj 	return (1);
1612479Swnj }
1622479Swnj 
1632605Swnj /*ARGSUSED*/
1642605Swnj dmattach(ui)
1652974Swnj 	struct uba_device *ui;
1662479Swnj {
1672479Swnj 
1682479Swnj 	/* no local state to set up */
1692479Swnj }
1702479Swnj 
1712479Swnj /*
1722468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1732468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1742468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
17513Sbill  */
17613Sbill /*ARGSUSED*/
17713Sbill dhopen(dev, flag)
1782395Swnj 	dev_t dev;
17913Sbill {
18013Sbill 	register struct tty *tp;
1812395Swnj 	register int unit, dh;
1822479Swnj 	register struct dhdevice *addr;
1832974Swnj 	register struct uba_device *ui;
18413Sbill 	int s;
18513Sbill 
1862395Swnj 	unit = minor(dev);
1872395Swnj 	dh = unit >> 4;
1888566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
1898566Sroot 		return (ENXIO);
1902395Swnj 	tp = &dh11[unit];
1918566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
1928566Sroot 		return (EBUSY);
1932479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
19413Sbill 	tp->t_addr = (caddr_t)addr;
19513Sbill 	tp->t_oproc = dhstart;
1965406Swnj 	tp->t_state |= TS_WOPEN;
1972468Swnj 	/*
1982468Swnj 	 * While setting up state for this uba and this dh,
1992468Swnj 	 * block uba resets which can clear the state.
2002468Swnj 	 */
2012468Swnj 	s = spl5();
20226219Skarels 	if (cbase[ui->ui_ubanum] == -1) {
20330322Skarels 		dh_uballoc[ui->ui_ubanum] = dh;
20430322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
20530322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
20613Sbill 	}
20716190Skarels 	if (timerstarted == 0) {
20816190Skarels 		timerstarted++;
20916190Skarels 		timeout(dhtimer, (caddr_t) 0, hz);
21016190Skarels 	}
2112456Swnj 	if ((dhact&(1<<dh)) == 0) {
2122456Swnj 		addr->un.dhcsr |= DH_IE;
2132468Swnj 		dhact |= (1<<dh);
21416190Skarels 		addr->dhsilo = 0;
2152456Swnj 	}
21613Sbill 	splx(s);
2172468Swnj 	/*
21827049Skarels 	 * If this is first open, initialize tty state to default.
2192468Swnj 	 */
2205406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
22113Sbill 		ttychars(tp);
22227049Skarels #ifndef PORTSELECTOR
22327049Skarels 		if (tp->t_ispeed == 0) {
22427049Skarels #else
22527049Skarels 			tp->t_state |= TS_HUPCLS;
22627049Skarels #endif PORTSELECTOR
22727049Skarels 			tp->t_ispeed = ISPEED;
22827049Skarels 			tp->t_ospeed = ISPEED;
22927049Skarels 			tp->t_flags = IFLAGS;
23027049Skarels #ifndef PORTSELECTOR
23127049Skarels 		}
23227049Skarels #endif PORTSELECTOR
2332395Swnj 		dhparam(unit);
23413Sbill 	}
2352468Swnj 	/*
2362468Swnj 	 * Wait for carrier, then process line discipline specific open.
2372468Swnj 	 */
23813Sbill 	dmopen(dev);
2398566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
24013Sbill }
24113Sbill 
24213Sbill /*
2432468Swnj  * Close a DH11 line, turning off the DM11.
24413Sbill  */
24513Sbill /*ARGSUSED*/
24613Sbill dhclose(dev, flag)
2472395Swnj 	dev_t dev;
2482395Swnj 	int flag;
24913Sbill {
25013Sbill 	register struct tty *tp;
2512395Swnj 	register unit;
25213Sbill 
2532395Swnj 	unit = minor(dev);
2542395Swnj 	tp = &dh11[unit];
25513Sbill 	(*linesw[tp->t_line].l_close)(tp);
2562479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
2575406Swnj 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
2582479Swnj 		dmctl(unit, DML_OFF, DMSET);
25913Sbill 	ttyclose(tp);
26013Sbill }
26113Sbill 
2627725Sroot dhread(dev, uio)
2632395Swnj 	dev_t dev;
2647725Sroot 	struct uio *uio;
26513Sbill {
2668490Sroot 	register struct tty *tp = &dh11[minor(dev)];
26713Sbill 
2687725Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
26913Sbill }
27013Sbill 
2717831Sroot dhwrite(dev, uio)
2722395Swnj 	dev_t dev;
2737831Sroot 	struct uio *uio;
27413Sbill {
2758490Sroot 	register struct tty *tp = &dh11[minor(dev)];
27613Sbill 
2778490Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
27813Sbill }
27913Sbill 
28013Sbill /*
28113Sbill  * DH11 receiver interrupt.
28213Sbill  */
2832395Swnj dhrint(dh)
2842395Swnj 	int dh;
28513Sbill {
28613Sbill 	register struct tty *tp;
2872395Swnj 	register c;
2882479Swnj 	register struct dhdevice *addr;
289117Sbill 	register struct tty *tp0;
2902974Swnj 	register struct uba_device *ui;
2912924Swnj 	int overrun = 0;
29213Sbill 
2932395Swnj 	ui = dhinfo[dh];
2942479Swnj 	if (ui == 0 || ui->ui_alive == 0)
2952479Swnj 		return;
2962479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
2972468Swnj 	tp0 = &dh11[dh<<4];
2982468Swnj 	/*
2992468Swnj 	 * Loop fetching characters from the silo for this
3002468Swnj 	 * dh until there are no more in the silo.
3012468Swnj 	 */
3022468Swnj 	while ((c = addr->dhrcr) < 0) {
3032468Swnj 		tp = tp0 + ((c>>8)&0xf);
30416190Skarels 		dhchars[dh]++;
3055406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
30625394Skarels 			wakeup((caddr_t)&tp->t_rawq);
30725394Skarels #ifdef PORTSELECTOR
30825394Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
3096615Ssam #endif
31025394Skarels 				continue;
31113Sbill 		}
3122468Swnj 		if (c & DH_PE)
31313Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
31413Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
31513Sbill 				continue;
3162924Swnj 		if ((c & DH_DO) && overrun == 0) {
31724840Seric 			log(LOG_WARNING, "dh%d: silo overflow\n", dh);
3182924Swnj 			overrun = 1;
3192924Swnj 		}
3202468Swnj 		if (c & DH_FE)
3212468Swnj 			/*
3222468Swnj 			 * At framing error (break) generate
3232468Swnj 			 * a null (in raw mode, for getty), or a
3242468Swnj 			 * interrupt (in cooked/cbreak mode).
3252468Swnj 			 */
32613Sbill 			if (tp->t_flags&RAW)
3272468Swnj 				c = 0;
32813Sbill 			else
3299549Ssam 				c = tp->t_intrc;
3302730Swnj #if NBK > 0
331139Sbill 		if (tp->t_line == NETLDISC) {
332117Sbill 			c &= 0177;
333168Sbill 			BKINPUT(c, tp);
334117Sbill 		} else
3352730Swnj #endif
3362468Swnj 			(*linesw[tp->t_line].l_rint)(c, tp);
33713Sbill 	}
33813Sbill }
33913Sbill 
34013Sbill /*
3412468Swnj  * Ioctl for DH11.
34213Sbill  */
34313Sbill /*ARGSUSED*/
3447629Ssam dhioctl(dev, cmd, data, flag)
3457629Ssam 	caddr_t data;
34613Sbill {
34713Sbill 	register struct tty *tp;
3488566Sroot 	register int unit = minor(dev);
3498566Sroot 	int error;
35013Sbill 
3512395Swnj 	tp = &dh11[unit];
3528566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3538566Sroot 	if (error >= 0)
3548566Sroot 		return (error);
3558566Sroot 	error = ttioctl(tp, cmd, data, flag);
3568566Sroot 	if (error >= 0) {
35717561Sbloom 		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
35817561Sbloom 		    cmd == TIOCLBIC || cmd == TIOCLSET)
3592395Swnj 			dhparam(unit);
3608566Sroot 		return (error);
3618566Sroot 	}
3628566Sroot 	switch (cmd) {
3637629Ssam 
364168Sbill 	case TIOCSBRK:
3652479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
366168Sbill 		break;
3677629Ssam 
368168Sbill 	case TIOCCBRK:
3692479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
370168Sbill 		break;
3717629Ssam 
372168Sbill 	case TIOCSDTR:
3732479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
374168Sbill 		break;
3757629Ssam 
376168Sbill 	case TIOCCDTR:
3772479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
378168Sbill 		break;
3797629Ssam 
380168Sbill 	default:
3818566Sroot 		return (ENOTTY);
382168Sbill 	}
3838566Sroot 	return (0);
38413Sbill }
38513Sbill 
38613Sbill /*
38713Sbill  * Set parameters from open or stty into the DH hardware
38813Sbill  * registers.
38913Sbill  */
3902395Swnj dhparam(unit)
3912395Swnj 	register int unit;
39213Sbill {
39313Sbill 	register struct tty *tp;
3942479Swnj 	register struct dhdevice *addr;
3952395Swnj 	register int lpar;
396300Sbill 	int s;
39713Sbill 
3982395Swnj 	tp = &dh11[unit];
3992479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4002468Swnj 	/*
4012468Swnj 	 * Block interrupts so parameters will be set
4022468Swnj 	 * before the line interrupts.
4032468Swnj 	 */
404300Sbill 	s = spl5();
4052468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
40613Sbill 	if ((tp->t_ispeed)==0) {
4075406Swnj 		tp->t_state |= TS_HUPCLS;
4082479Swnj 		dmctl(unit, DML_OFF, DMSET);
40928147Skarels 		splx(s);
41013Sbill 		return;
41113Sbill 	}
4122395Swnj 	lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
4132468Swnj 	if ((tp->t_ispeed) == B134)
4142395Swnj 		lpar |= BITS6|PENABLE|HDUPLX;
41524269Slepreau 	else if (tp->t_flags & (RAW|LITOUT|PASS8))
4162395Swnj 		lpar |= BITS8;
41713Sbill 	else
4182395Swnj 		lpar |= BITS7|PENABLE;
41913Sbill 	if ((tp->t_flags&EVENP) == 0)
4202395Swnj 		lpar |= OPAR;
4212468Swnj 	if ((tp->t_ospeed) == B110)
4222395Swnj 		lpar |= TWOSB;
4232395Swnj 	addr->dhlpr = lpar;
424300Sbill 	splx(s);
42513Sbill }
42613Sbill 
42713Sbill /*
42813Sbill  * DH11 transmitter interrupt.
42913Sbill  * Restart each line which used to be active but has
43013Sbill  * terminated transmission since the last interrupt.
43113Sbill  */
4322395Swnj dhxint(dh)
4332395Swnj 	int dh;
43413Sbill {
43513Sbill 	register struct tty *tp;
4362479Swnj 	register struct dhdevice *addr;
43713Sbill 	short ttybit, bar, *sbar;
4382974Swnj 	register struct uba_device *ui;
4392468Swnj 	register int unit;
4402605Swnj 	u_short cntr;
44113Sbill 
4422395Swnj 	ui = dhinfo[dh];
4432479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4442456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4452456Swnj 		addr->un.dhcsr |= DH_CNI;
4462924Swnj 		printf("dh%d: NXM\n", dh);
447105Sbill 	}
4482395Swnj 	sbar = &dhsar[dh];
44913Sbill 	bar = *sbar & ~addr->dhbar;
4502395Swnj 	unit = dh * 16; ttybit = 1;
4512468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4522468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4532468Swnj 		if (bar & ttybit) {
45413Sbill 			*sbar &= ~ttybit;
45513Sbill 			bar &= ~ttybit;
4562395Swnj 			tp = &dh11[unit];
4575406Swnj 			tp->t_state &= ~TS_BUSY;
4585406Swnj 			if (tp->t_state&TS_FLUSH)
4595406Swnj 				tp->t_state &= ~TS_FLUSH;
460113Sbill 			else {
4612456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4622468Swnj 				/*
4632468Swnj 				 * Do arithmetic in a short to make up
4642468Swnj 				 * for lost 16&17 bits.
4652468Swnj 				 */
4662605Swnj 				cntr = addr->dhcar -
4672468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4683101Swnj 				ndflush(&tp->t_outq, (int)cntr);
469113Sbill 			}
470113Sbill 			if (tp->t_line)
47113Sbill 				(*linesw[tp->t_line].l_start)(tp);
472113Sbill 			else
47313Sbill 				dhstart(tp);
47413Sbill 		}
47513Sbill 	}
47613Sbill }
47713Sbill 
47813Sbill /*
47913Sbill  * Start (restart) transmission on the given DH11 line.
48013Sbill  */
48113Sbill dhstart(tp)
4822395Swnj 	register struct tty *tp;
48313Sbill {
4842479Swnj 	register struct dhdevice *addr;
4852468Swnj 	register int car, dh, unit, nch;
4862395Swnj 	int s;
48713Sbill 
4882468Swnj 	unit = minor(tp->t_dev);
4892468Swnj 	dh = unit >> 4;
4902468Swnj 	unit &= 0xf;
4912479Swnj 	addr = (struct dhdevice *)tp->t_addr;
4922468Swnj 
49313Sbill 	/*
4942468Swnj 	 * Must hold interrupts in following code to prevent
4952468Swnj 	 * state of the tp from changing.
49613Sbill 	 */
49713Sbill 	s = spl5();
4982468Swnj 	/*
4992468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5002468Swnj 	 */
5015406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
50213Sbill 		goto out;
5032468Swnj 	/*
5042468Swnj 	 * If there are sleepers, and output has drained below low
5052468Swnj 	 * water mark, wake up the sleepers.
5062468Swnj 	 */
5075406Swnj 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
5085406Swnj 		if (tp->t_state&TS_ASLEEP) {
5095406Swnj 			tp->t_state &= ~TS_ASLEEP;
5105406Swnj 			wakeup((caddr_t)&tp->t_outq);
5115406Swnj 		}
5125406Swnj 		if (tp->t_wsel) {
5135406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5145406Swnj 			tp->t_wsel = 0;
5155406Swnj 			tp->t_state &= ~TS_WCOLL;
5165406Swnj 		}
51713Sbill 	}
5182468Swnj 	/*
5192468Swnj 	 * Now restart transmission unless the output queue is
5202468Swnj 	 * empty.
5212468Swnj 	 */
52213Sbill 	if (tp->t_outq.c_cc == 0)
52313Sbill 		goto out;
5249549Ssam 	if (tp->t_flags & (RAW|LITOUT))
52513Sbill 		nch = ndqb(&tp->t_outq, 0);
5262395Swnj 	else {
52713Sbill 		nch = ndqb(&tp->t_outq, 0200);
5282468Swnj 		/*
5292468Swnj 		 * If first thing on queue is a delay process it.
5302468Swnj 		 */
53113Sbill 		if (nch == 0) {
53213Sbill 			nch = getc(&tp->t_outq);
5332468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5345406Swnj 			tp->t_state |= TS_TIMEOUT;
53513Sbill 			goto out;
53613Sbill 		}
53713Sbill 	}
5382468Swnj 	/*
5392468Swnj 	 * If characters to transmit, restart transmission.
5402468Swnj 	 */
54113Sbill 	if (nch) {
5422468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5432468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5443586Sroot 		/*
5453586Sroot 		 * The following nonsense with short word
5463586Sroot 		 * is to make sure the dhbar |= word below
5473586Sroot 		 * is done with an interlocking bisw2 instruction.
5483586Sroot 		 */
5493586Sroot 		{ short word = 1 << unit;
5503586Sroot 		dhsar[dh] |= word;
5512468Swnj 		addr->dhcar = car;
55213Sbill 		addr->dhbcr = -nch;
5533586Sroot 		addr->dhbar |= word;
5543586Sroot 		}
5555406Swnj 		tp->t_state |= TS_BUSY;
55613Sbill 	}
5572395Swnj out:
55813Sbill 	splx(s);
55913Sbill }
56013Sbill 
56113Sbill /*
5622468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
56313Sbill  */
56413Sbill /*ARGSUSED*/
56513Sbill dhstop(tp, flag)
5662468Swnj 	register struct tty *tp;
56713Sbill {
5682479Swnj 	register struct dhdevice *addr;
5692395Swnj 	register int unit, s;
57013Sbill 
5712479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5722468Swnj 	/*
5732468Swnj 	 * Block input/output interrupts while messing with state.
5742468Swnj 	 */
5752468Swnj 	s = spl5();
5765406Swnj 	if (tp->t_state & TS_BUSY) {
5772468Swnj 		/*
5782468Swnj 		 * Device is transmitting; stop output
5792468Swnj 		 * by selecting the line and setting the byte
5802468Swnj 		 * count to -1.  We will clean up later
5812468Swnj 		 * by examining the address where the dh stopped.
5822468Swnj 		 */
5832395Swnj 		unit = minor(tp->t_dev);
5842456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
5855406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
5865406Swnj 			tp->t_state |= TS_FLUSH;
587113Sbill 		addr->dhbcr = -1;
588113Sbill 	}
58913Sbill 	splx(s);
59013Sbill }
59113Sbill 
592168Sbill /*
593280Sbill  * Reset state of driver if UBA reset was necessary.
594280Sbill  * Reset the csrl and lpr registers on open lines, and
595280Sbill  * restart transmitters.
596280Sbill  */
5972395Swnj dhreset(uban)
5982468Swnj 	int uban;
599280Sbill {
6002395Swnj 	register int dh, unit;
601280Sbill 	register struct tty *tp;
6022974Swnj 	register struct uba_device *ui;
6032421Skre 	int i;
604280Sbill 
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);
61130322Skarels 		if (dh_uballoc[uban] == dh) {
61230322Skarels 			int info;
61330322Skarels 
61430322Skarels 			info = uballoc(uban, (caddr_t)cfree,
61530322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
61630322Skarels 			if (info)
61730322Skarels 				cbase[uban] = UBAI_ADDR(info);
61830322Skarels 			else {
61930322Skarels 				printf(" [can't get uba map]");
62030322Skarels 				cbase[uban] = -1;
62130322Skarels 			}
62225433Skarels 		}
6232479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
62416190Skarels 		((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
6252421Skre 		unit = dh * 16;
6262421Skre 		for (i = 0; i < 16; i++) {
6272421Skre 			tp = &dh11[unit];
6285406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6292421Skre 				dhparam(unit);
6302479Swnj 				dmctl(unit, DML_ON, DMSET);
6315406Swnj 				tp->t_state &= ~TS_BUSY;
6322421Skre 				dhstart(tp);
6332421Skre 			}
6342421Skre 			unit++;
635300Sbill 		}
636300Sbill 	}
63716190Skarels 	dhsilos = 0;
638280Sbill }
6392395Swnj 
64016190Skarels int dhtransitions, dhslowtimers, dhfasttimers;		/*DEBUG*/
6412468Swnj /*
64216190Skarels  * At software clock interrupt time, check status.
64316190Skarels  * Empty all the dh silos that are in use, and decide whether
64416190Skarels  * to turn any silos off or on.
6452468Swnj  */
6462456Swnj dhtimer()
6472456Swnj {
64816190Skarels 	register int dh, s;
64916190Skarels 	static int timercalls;
6502456Swnj 
65116190Skarels 	if (dhsilos) {
65216190Skarels 		dhfasttimers++;		/*DEBUG*/
65316190Skarels 		timercalls++;
65416190Skarels 		s = spl5();
65516190Skarels 		for (dh = 0; dh < NDH; dh++)
65616190Skarels 			if (dhsilos & (1 << dh))
65716190Skarels 				dhrint(dh);
65816190Skarels 		splx(s);
65916190Skarels 	}
66016190Skarels 	if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
66116190Skarels 		dhslowtimers++;		/*DEBUG*/
66216190Skarels 		timercalls = 0;
66316190Skarels 		for (dh = 0; dh < NDH; dh++) {
66416190Skarels 		    ave(dhrate[dh], dhchars[dh], 8);
66516190Skarels 		    if ((dhchars[dh] > dhhighrate) &&
66616190Skarels 		      ((dhsilos & (1 << dh)) == 0)) {
66716190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
66816190Skarels 			    (dhchars[dh] > 500? 32 : 16);
66916190Skarels 			dhsilos |= (1 << dh);
67016190Skarels 			dhtransitions++;		/*DEBUG*/
67116190Skarels 		    } else if ((dhsilos & (1 << dh)) &&
67216190Skarels 		      (dhrate[dh] < dhlowrate)) {
67316190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
67416190Skarels 			dhsilos &= ~(1 << dh);
67516190Skarels 		    }
67616190Skarels 		    dhchars[dh] = 0;
67716190Skarels 		}
67816190Skarels 	}
67916190Skarels 	timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
6802456Swnj }
6812456Swnj 
6822468Swnj /*
6832479Swnj  * Turn on the line associated with dh dev.
6842468Swnj  */
6852468Swnj dmopen(dev)
6862468Swnj 	dev_t dev;
6872468Swnj {
6882468Swnj 	register struct tty *tp;
6892468Swnj 	register struct dmdevice *addr;
6902974Swnj 	register struct uba_device *ui;
6912468Swnj 	register int unit;
6922468Swnj 	register int dm;
6933792Swnj 	int s;
6942468Swnj 
6952468Swnj 	unit = minor(dev);
6962479Swnj 	dm = unit >> 4;
6972468Swnj 	tp = &dh11[unit];
6982566Swnj 	unit &= 0xf;
69916942Skarels 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
7005406Swnj 		tp->t_state |= TS_CARR_ON;
7012468Swnj 		return;
7022468Swnj 	}
7032468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7043792Swnj 	s = spl5();
70530341Skarels 	for (;;) {
70630341Skarels 		addr->dmcsr &= ~DM_SE;
70730341Skarels 		while (addr->dmcsr & DM_BUSY)
70830341Skarels 			;
70930341Skarels 		addr->dmcsr = unit;
71030341Skarels 		addr->dmlstat = DML_ON;
711*30349Skarels 		if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit)))
71230341Skarels 			tp->t_state |= TS_CARR_ON;
71330341Skarels 		addr->dmcsr = DM_IE|DM_SE;
71430341Skarels 		if (tp->t_state & TS_CARR_ON)
71530341Skarels 			break;
7162468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
71730341Skarels 	}
7183792Swnj 	splx(s);
7192468Swnj }
7202468Swnj 
7212468Swnj /*
7222468Swnj  * Dump control bits into the DM registers.
7232468Swnj  */
7242468Swnj dmctl(dev, bits, how)
7252468Swnj 	dev_t dev;
7262468Swnj 	int bits, how;
7272468Swnj {
7282974Swnj 	register struct uba_device *ui;
7292468Swnj 	register struct dmdevice *addr;
7302468Swnj 	register int unit, s;
7312468Swnj 	int dm;
7322468Swnj 
7332468Swnj 	unit = minor(dev);
7342468Swnj 	dm = unit >> 4;
7352468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7362468Swnj 		return;
7372468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7382468Swnj 	s = spl5();
7392479Swnj 	addr->dmcsr &= ~DM_SE;
7402479Swnj 	while (addr->dmcsr & DM_BUSY)
7412468Swnj 		;
7422468Swnj 	addr->dmcsr = unit & 0xf;
7432468Swnj 	switch(how) {
7442468Swnj 	case DMSET:
7452468Swnj 		addr->dmlstat = bits;
7462468Swnj 		break;
7472468Swnj 	case DMBIS:
7482468Swnj 		addr->dmlstat |= bits;
7492468Swnj 		break;
7502468Swnj 	case DMBIC:
7512468Swnj 		addr->dmlstat &= ~bits;
7522468Swnj 		break;
7532468Swnj 	}
7543792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7552468Swnj 	splx(s);
7562468Swnj }
7572468Swnj 
7582468Swnj /*
7592468Swnj  * DM11 interrupt; deal with carrier transitions.
7602468Swnj  */
7612468Swnj dmintr(dm)
7622468Swnj 	register int dm;
7632468Swnj {
7642974Swnj 	register struct uba_device *ui;
7652468Swnj 	register struct tty *tp;
7662468Swnj 	register struct dmdevice *addr;
76716942Skarels 	int unit;
7682468Swnj 
7692468Swnj 	ui = dminfo[dm];
7702479Swnj 	if (ui == 0)
7712479Swnj 		return;
7722468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7733997Sroot 	if (addr->dmcsr&DM_DONE) {
7743997Sroot 		if (addr->dmcsr&DM_CF) {
77516942Skarels 			unit = addr->dmcsr & 0xf;
77616942Skarels 			tp = &dh11[(dm << 4) + unit];
77725394Skarels 			if (addr->dmlstat & DML_CAR)
77825394Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
77925394Skarels 			else if ((dhsoftCAR[dm] & (1<<unit)) == 0 &&
78025394Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
78125394Skarels 				addr->dmlstat = 0;
7823997Sroot 		}
7833997Sroot 		addr->dmcsr = DM_IE|DM_SE;
7842468Swnj 	}
7852468Swnj }
7862625Swnj #endif
787