xref: /csrg-svn/sys/vax/uba/dh.c (revision 39061)
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*39061Smarc  *	@(#)dh.c	7.8 (Berkeley) 09/06/89
723320Smckusick  */
813Sbill 
91934Swnj #include "dh.h"
102643Swnj #if NDH > 0
1113Sbill /*
122479Swnj  * DH-11/DM-11 driver
1313Sbill  */
1437511Smckusick #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
58*39061Smarc #define	ISPEED	TTYDEF_SPEED
59*39061Smarc #define	LFLAG	TTYDEF_LFLAG
606615Ssam #else
616615Ssam #define	ISPEED	B4800
62*39061Smarc #define	LFLAG	(TTYDEF_LFLAG&~ECHO)
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 
84*39061Smarc struct speedtab dhspeedtab[] = {
85*39061Smarc 	19200,	14,
86*39061Smarc 	9600,	13,
87*39061Smarc 	4800,	12,
88*39061Smarc 	2400,	11,
89*39061Smarc 	1800,	10,
90*39061Smarc 	1200,	9,
91*39061Smarc 	600,	8,
92*39061Smarc 	300,	7,
93*39061Smarc 	200,	6,
94*39061Smarc 	150,	5,
95*39061Smarc 	134,	4,
96*39061Smarc 	110,	3,
97*39061Smarc 	75,	2,
98*39061Smarc 	50,	1,
99*39061Smarc 	0,	0,
100*39061Smarc 	EXTA,	14,
101*39061Smarc 	EXTB,	15,
102*39061Smarc 	-1,	-1
103*39061Smarc };
104*39061Smarc 
1052479Swnj /*
10630322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
10730322Skarels  * The identity of the board which allocated resources is recorded,
10830322Skarels  * so the process may be repeated after UNIBUS resets.
1092479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1102479Swnj  * into an i/o space address for the DMA routine.
1112479Swnj  */
11230322Skarels int	dh_uballoc[NUBA];	/* which dh (if any) allocated unibus map */
11330322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
1142479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
11513Sbill 
1162456Swnj /*
1172456Swnj  * Routine for configuration to force a dh to interrupt.
1182456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1192456Swnj  */
1202468Swnj /*ARGSUSED*/
1212605Swnj dhprobe(reg)
1222395Swnj 	caddr_t reg;
1232395Swnj {
1242468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1252479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1262395Swnj 
1272605Swnj #ifdef lint
1282605Swnj 	br = 0; cvec = br; br = cvec;
1297384Sroot 	if (ndh11 == 0) ndh11 = 1;
1304932Swnj 	dhrint(0); dhxint(0);
1312605Swnj #endif
1322696Swnj #ifndef notdef
1332566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1346380Swnj 	DELAY(1000);
1357384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1362566Swnj 	dhaddr->un.dhcsr = 0;
1372566Swnj #else
1382456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1392456Swnj 	DELAY(5);
1402456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1412421Skre 	dhaddr->dhbcr = -1;
1422456Swnj 	dhaddr->dhcar = 0;
1432421Skre 	dhaddr->dhbar = 1;
1442456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1452421Skre 	dhaddr->un.dhcsr = 0;
1462456Swnj 	if (cvec && cvec != 0x200)
1472456Swnj 		cvec -= 4;		/* transmit -> receive */
1482482Swnj #endif
1497408Skre 	return (sizeof (struct dhdevice));
1502395Swnj }
1512395Swnj 
1522456Swnj /*
1532605Swnj  * Routine called to attach a dh.
1542456Swnj  */
1552605Swnj dhattach(ui)
1562974Swnj 	struct uba_device *ui;
1572395Swnj {
1582395Swnj 
1592566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
16026219Skarels 	cbase[ui->ui_ubanum] = -1;
16136610Sbostic 	dh_uballoc[ui->ui_ubanum] = -1;
1622395Swnj }
1632395Swnj 
16413Sbill /*
1652479Swnj  * Configuration routine to cause a dm to interrupt.
1662479Swnj  */
1672605Swnj dmprobe(reg)
1682605Swnj 	caddr_t reg;
1692479Swnj {
1702479Swnj 	register int br, vec;			/* value-result */
1712605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1722479Swnj 
1732605Swnj #ifdef lint
1743101Swnj 	br = 0; vec = br; br = vec;
1756185Ssam 	dmintr(0);
1762605Swnj #endif
1772479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1782479Swnj 	DELAY(20);
1792479Swnj 	dmaddr->dmcsr = 0;
1802605Swnj 	return (1);
1812479Swnj }
1822479Swnj 
1832605Swnj /*ARGSUSED*/
1842605Swnj dmattach(ui)
1852974Swnj 	struct uba_device *ui;
1862479Swnj {
1872479Swnj 
1882479Swnj 	/* no local state to set up */
1892479Swnj }
1902479Swnj 
1912479Swnj /*
1922468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1932468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1942468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
19513Sbill  */
19613Sbill /*ARGSUSED*/
19713Sbill dhopen(dev, flag)
1982395Swnj 	dev_t dev;
19913Sbill {
20013Sbill 	register struct tty *tp;
2012395Swnj 	register int unit, dh;
2022479Swnj 	register struct dhdevice *addr;
2032974Swnj 	register struct uba_device *ui;
20413Sbill 	int s;
205*39061Smarc 	int dhparam();
20613Sbill 
2072395Swnj 	unit = minor(dev);
2082395Swnj 	dh = unit >> 4;
2098566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
2108566Sroot 		return (ENXIO);
2112395Swnj 	tp = &dh11[unit];
2128566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
2138566Sroot 		return (EBUSY);
2142479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
21513Sbill 	tp->t_addr = (caddr_t)addr;
21613Sbill 	tp->t_oproc = dhstart;
217*39061Smarc 	tp->t_param = dhparam;
218*39061Smarc 	tp->t_dev = dev;
2195406Swnj 	tp->t_state |= TS_WOPEN;
2202468Swnj 	/*
2212468Swnj 	 * While setting up state for this uba and this dh,
2222468Swnj 	 * block uba resets which can clear the state.
2232468Swnj 	 */
2242468Swnj 	s = spl5();
22526219Skarels 	if (cbase[ui->ui_ubanum] == -1) {
22630322Skarels 		dh_uballoc[ui->ui_ubanum] = dh;
22730322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22830322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22913Sbill 	}
23016190Skarels 	if (timerstarted == 0) {
23116190Skarels 		timerstarted++;
23216190Skarels 		timeout(dhtimer, (caddr_t) 0, hz);
23316190Skarels 	}
2342456Swnj 	if ((dhact&(1<<dh)) == 0) {
2352456Swnj 		addr->un.dhcsr |= DH_IE;
2362468Swnj 		dhact |= (1<<dh);
23716190Skarels 		addr->dhsilo = 0;
2382456Swnj 	}
23913Sbill 	splx(s);
2402468Swnj 	/*
24127049Skarels 	 * If this is first open, initialize tty state to default.
2422468Swnj 	 */
2435406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
24413Sbill 		ttychars(tp);
24527049Skarels #ifndef PORTSELECTOR
24627049Skarels 		if (tp->t_ispeed == 0) {
247*39061Smarc #endif
248*39061Smarc 			tp->t_iflag = TTYDEF_IFLAG;
249*39061Smarc 			tp->t_oflag = TTYDEF_OFLAG;
250*39061Smarc 			tp->t_cflag = TTYDEF_CFLAG;
251*39061Smarc 			tp->t_lflag = LFLAG;
252*39061Smarc 			tp->t_ispeed = tp->t_ospeed = ISPEED;
253*39061Smarc #ifdef PORTSELECTOR
254*39061Smarc 			tp->t_cflag |= HUPCL;
25527049Skarels #else
25627049Skarels 		}
257*39061Smarc #endif
258*39061Smarc 		dhparam(tp, &tp->t_termios);
259*39061Smarc 		ttsetwater(tp);
26013Sbill 	}
2612468Swnj 	/*
2622468Swnj 	 * Wait for carrier, then process line discipline specific open.
2632468Swnj 	 */
264*39061Smarc 	dmopen(dev, flag);
2658566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
26613Sbill }
26713Sbill 
26813Sbill /*
2692468Swnj  * Close a DH11 line, turning off the DM11.
27013Sbill  */
27113Sbill /*ARGSUSED*/
27213Sbill dhclose(dev, flag)
2732395Swnj 	dev_t dev;
2742395Swnj 	int flag;
27513Sbill {
27613Sbill 	register struct tty *tp;
2772395Swnj 	register unit;
27813Sbill 
2792395Swnj 	unit = minor(dev);
2802395Swnj 	tp = &dh11[unit];
28113Sbill 	(*linesw[tp->t_line].l_close)(tp);
2822479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
283*39061Smarc 	if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0)
2842479Swnj 		dmctl(unit, DML_OFF, DMSET);
28513Sbill 	ttyclose(tp);
28613Sbill }
28713Sbill 
288*39061Smarc dhread(dev, uio, flag)
2892395Swnj 	dev_t dev;
2907725Sroot 	struct uio *uio;
29113Sbill {
2928490Sroot 	register struct tty *tp = &dh11[minor(dev)];
29313Sbill 
294*39061Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
29513Sbill }
29613Sbill 
297*39061Smarc dhwrite(dev, uio, flag)
2982395Swnj 	dev_t dev;
2997831Sroot 	struct uio *uio;
30013Sbill {
3018490Sroot 	register struct tty *tp = &dh11[minor(dev)];
30213Sbill 
303*39061Smarc 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
30413Sbill }
30513Sbill 
30613Sbill /*
30713Sbill  * DH11 receiver interrupt.
30813Sbill  */
3092395Swnj dhrint(dh)
3102395Swnj 	int dh;
31113Sbill {
31213Sbill 	register struct tty *tp;
313*39061Smarc 	register c, cc;
3142479Swnj 	register struct dhdevice *addr;
315117Sbill 	register struct tty *tp0;
3162974Swnj 	register struct uba_device *ui;
3172924Swnj 	int overrun = 0;
31813Sbill 
3192395Swnj 	ui = dhinfo[dh];
3202479Swnj 	if (ui == 0 || ui->ui_alive == 0)
3212479Swnj 		return;
3222479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3232468Swnj 	tp0 = &dh11[dh<<4];
3242468Swnj 	/*
3252468Swnj 	 * Loop fetching characters from the silo for this
3262468Swnj 	 * dh until there are no more in the silo.
3272468Swnj 	 */
3282468Swnj 	while ((c = addr->dhrcr) < 0) {
3292468Swnj 		tp = tp0 + ((c>>8)&0xf);
33016190Skarels 		dhchars[dh]++;
3315406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
33225394Skarels 			wakeup((caddr_t)&tp->t_rawq);
33325394Skarels #ifdef PORTSELECTOR
33425394Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
3356615Ssam #endif
33625394Skarels 				continue;
33713Sbill 		}
338*39061Smarc 		cc = c&0xff;
339*39061Smarc 		if (c&DH_PE)
340*39061Smarc 			cc |= TTY_PE;
341*39061Smarc 		if ((c&DH_DO) && overrun == 0) {
34224840Seric 			log(LOG_WARNING, "dh%d: silo overflow\n", dh);
3432924Swnj 			overrun = 1;
3442924Swnj 		}
345*39061Smarc 		if (c&DH_FE)
346*39061Smarc 			cc |= TTY_FE;
347*39061Smarc 		(*linesw[tp->t_line].l_rint)(cc, tp);
34813Sbill 	}
34913Sbill }
35013Sbill 
35113Sbill /*
3522468Swnj  * Ioctl for DH11.
35313Sbill  */
35413Sbill /*ARGSUSED*/
3557629Ssam dhioctl(dev, cmd, data, flag)
3567629Ssam 	caddr_t data;
35713Sbill {
35813Sbill 	register struct tty *tp;
3598566Sroot 	register int unit = minor(dev);
3608566Sroot 	int error;
36113Sbill 
3622395Swnj 	tp = &dh11[unit];
3638566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3648566Sroot 	if (error >= 0)
3658566Sroot 		return (error);
3668566Sroot 	error = ttioctl(tp, cmd, data, flag);
367*39061Smarc 	if (error >= 0)
3688566Sroot 		return (error);
3698566Sroot 	switch (cmd) {
3707629Ssam 
371168Sbill 	case TIOCSBRK:
3722479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
373168Sbill 		break;
3747629Ssam 
375168Sbill 	case TIOCCBRK:
3762479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
377168Sbill 		break;
3787629Ssam 
379168Sbill 	case TIOCSDTR:
3802479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
381168Sbill 		break;
3827629Ssam 
383168Sbill 	case TIOCCDTR:
3842479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
385168Sbill 		break;
3867629Ssam 
387168Sbill 	default:
3888566Sroot 		return (ENOTTY);
389168Sbill 	}
3908566Sroot 	return (0);
39113Sbill }
39213Sbill 
39313Sbill /*
39413Sbill  * Set parameters from open or stty into the DH hardware
39513Sbill  * registers.
39613Sbill  */
397*39061Smarc dhparam(tp, t)
398*39061Smarc 	register struct tty *tp;
399*39061Smarc 	register struct termios *t;
40013Sbill {
4012479Swnj 	register struct dhdevice *addr;
4022395Swnj 	register int lpar;
403*39061Smarc 	register int cflag = t->c_cflag;
404*39061Smarc 	int unit = minor(tp->t_dev);
405300Sbill 	int s;
406*39061Smarc 	int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab);
407*39061Smarc 	int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab);
40813Sbill 
409*39061Smarc 	/* check requested parameters */
410*39061Smarc 	if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
411*39061Smarc 		return(EINVAL);
412*39061Smarc 	if (ispeed == 0)
413*39061Smarc 		ispeed = ospeed;
414*39061Smarc 	/* and copy to tty */
415*39061Smarc 	tp->t_ispeed = t->c_ispeed;
416*39061Smarc 	tp->t_ospeed = t->c_ospeed;
417*39061Smarc 	tp->t_cflag = cflag;
4182468Swnj 	/*
4192468Swnj 	 * Block interrupts so parameters will be set
4202468Swnj 	 * before the line interrupts.
4212468Swnj 	 */
422*39061Smarc 	addr = (struct dhdevice *)tp->t_addr;
423300Sbill 	s = spl5();
4242468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
425*39061Smarc 	if (ospeed == 0) {
426*39061Smarc 		tp->t_cflag |= HUPCL;
4272479Swnj 		dmctl(unit, DML_OFF, DMSET);
42828147Skarels 		splx(s);
429*39061Smarc 		return 0;
43013Sbill 	}
431*39061Smarc 	lpar = (ospeed<<10) | (ispeed<<6);
432*39061Smarc 	switch (cflag&CSIZE) {
433*39061Smarc 	case CS6:	lpar |= BITS6; break;
434*39061Smarc 	case CS7:	lpar |= BITS7; break;
435*39061Smarc 	case CS8:	lpar |= BITS8; break;
436*39061Smarc 	}
437*39061Smarc 	if (cflag&PARENB)
438*39061Smarc 		lpar |= PENABLE;
439*39061Smarc 	if (cflag&PARODD)
4402395Swnj 		lpar |= OPAR;
441*39061Smarc 	if (cflag&CSTOPB)
4422395Swnj 		lpar |= TWOSB;
4432395Swnj 	addr->dhlpr = lpar;
444300Sbill 	splx(s);
445*39061Smarc 	return 0;
44613Sbill }
44713Sbill 
44813Sbill /*
44913Sbill  * DH11 transmitter interrupt.
45013Sbill  * Restart each line which used to be active but has
45113Sbill  * terminated transmission since the last interrupt.
45213Sbill  */
4532395Swnj dhxint(dh)
4542395Swnj 	int dh;
45513Sbill {
45613Sbill 	register struct tty *tp;
4572479Swnj 	register struct dhdevice *addr;
45813Sbill 	short ttybit, bar, *sbar;
4592974Swnj 	register struct uba_device *ui;
4602468Swnj 	register int unit;
4612605Swnj 	u_short cntr;
46213Sbill 
4632395Swnj 	ui = dhinfo[dh];
4642479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4652456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4662456Swnj 		addr->un.dhcsr |= DH_CNI;
4672924Swnj 		printf("dh%d: NXM\n", dh);
468105Sbill 	}
4692395Swnj 	sbar = &dhsar[dh];
47013Sbill 	bar = *sbar & ~addr->dhbar;
4712395Swnj 	unit = dh * 16; ttybit = 1;
4722468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4732468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4742468Swnj 		if (bar & ttybit) {
47513Sbill 			*sbar &= ~ttybit;
47613Sbill 			bar &= ~ttybit;
4772395Swnj 			tp = &dh11[unit];
4785406Swnj 			tp->t_state &= ~TS_BUSY;
4795406Swnj 			if (tp->t_state&TS_FLUSH)
4805406Swnj 				tp->t_state &= ~TS_FLUSH;
481113Sbill 			else {
4822456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4832468Swnj 				/*
4842468Swnj 				 * Do arithmetic in a short to make up
4852468Swnj 				 * for lost 16&17 bits.
4862468Swnj 				 */
4872605Swnj 				cntr = addr->dhcar -
4882468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4893101Swnj 				ndflush(&tp->t_outq, (int)cntr);
490113Sbill 			}
491113Sbill 			if (tp->t_line)
49213Sbill 				(*linesw[tp->t_line].l_start)(tp);
493113Sbill 			else
49413Sbill 				dhstart(tp);
49513Sbill 		}
49613Sbill 	}
49713Sbill }
49813Sbill 
49913Sbill /*
50013Sbill  * Start (restart) transmission on the given DH11 line.
50113Sbill  */
50213Sbill dhstart(tp)
5032395Swnj 	register struct tty *tp;
50413Sbill {
5052479Swnj 	register struct dhdevice *addr;
5062468Swnj 	register int car, dh, unit, nch;
5072395Swnj 	int s;
50813Sbill 
5092468Swnj 	unit = minor(tp->t_dev);
5102468Swnj 	dh = unit >> 4;
5112468Swnj 	unit &= 0xf;
5122479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5132468Swnj 
51413Sbill 	/*
5152468Swnj 	 * Must hold interrupts in following code to prevent
5162468Swnj 	 * state of the tp from changing.
51713Sbill 	 */
51813Sbill 	s = spl5();
5192468Swnj 	/*
5202468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5212468Swnj 	 */
5225406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
52313Sbill 		goto out;
5242468Swnj 	/*
5252468Swnj 	 * If there are sleepers, and output has drained below low
5262468Swnj 	 * water mark, wake up the sleepers.
5272468Swnj 	 */
528*39061Smarc 	if (tp->t_outq.c_cc<=tp->t_lowat) {
5295406Swnj 		if (tp->t_state&TS_ASLEEP) {
5305406Swnj 			tp->t_state &= ~TS_ASLEEP;
5315406Swnj 			wakeup((caddr_t)&tp->t_outq);
5325406Swnj 		}
5335406Swnj 		if (tp->t_wsel) {
5345406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5355406Swnj 			tp->t_wsel = 0;
5365406Swnj 			tp->t_state &= ~TS_WCOLL;
5375406Swnj 		}
53813Sbill 	}
5392468Swnj 	/*
5402468Swnj 	 * Now restart transmission unless the output queue is
5412468Swnj 	 * empty.
5422468Swnj 	 */
54313Sbill 	if (tp->t_outq.c_cc == 0)
54413Sbill 		goto out;
545*39061Smarc 	if (1 || !(tp->t_oflag&OPOST))	/*XXX*/
54613Sbill 		nch = ndqb(&tp->t_outq, 0);
5472395Swnj 	else {
54813Sbill 		nch = ndqb(&tp->t_outq, 0200);
5492468Swnj 		/*
5502468Swnj 		 * If first thing on queue is a delay process it.
5512468Swnj 		 */
55213Sbill 		if (nch == 0) {
55313Sbill 			nch = getc(&tp->t_outq);
5542468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5555406Swnj 			tp->t_state |= TS_TIMEOUT;
55613Sbill 			goto out;
55713Sbill 		}
55813Sbill 	}
5592468Swnj 	/*
5602468Swnj 	 * If characters to transmit, restart transmission.
5612468Swnj 	 */
56213Sbill 	if (nch) {
5632468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5642468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5653586Sroot 		/*
5663586Sroot 		 * The following nonsense with short word
5673586Sroot 		 * is to make sure the dhbar |= word below
5683586Sroot 		 * is done with an interlocking bisw2 instruction.
5693586Sroot 		 */
5703586Sroot 		{ short word = 1 << unit;
5713586Sroot 		dhsar[dh] |= word;
5722468Swnj 		addr->dhcar = car;
57313Sbill 		addr->dhbcr = -nch;
5743586Sroot 		addr->dhbar |= word;
5753586Sroot 		}
5765406Swnj 		tp->t_state |= TS_BUSY;
57713Sbill 	}
5782395Swnj out:
57913Sbill 	splx(s);
58013Sbill }
58113Sbill 
58213Sbill /*
5832468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
58413Sbill  */
58513Sbill /*ARGSUSED*/
58613Sbill dhstop(tp, flag)
5872468Swnj 	register struct tty *tp;
58813Sbill {
5892479Swnj 	register struct dhdevice *addr;
5902395Swnj 	register int unit, s;
59113Sbill 
5922479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5932468Swnj 	/*
5942468Swnj 	 * Block input/output interrupts while messing with state.
5952468Swnj 	 */
5962468Swnj 	s = spl5();
5975406Swnj 	if (tp->t_state & TS_BUSY) {
5982468Swnj 		/*
5992468Swnj 		 * Device is transmitting; stop output
6002468Swnj 		 * by selecting the line and setting the byte
6012468Swnj 		 * count to -1.  We will clean up later
6022468Swnj 		 * by examining the address where the dh stopped.
6032468Swnj 		 */
6042395Swnj 		unit = minor(tp->t_dev);
6052456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
6065406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
6075406Swnj 			tp->t_state |= TS_FLUSH;
608113Sbill 		addr->dhbcr = -1;
609113Sbill 	}
61013Sbill 	splx(s);
61113Sbill }
61213Sbill 
613168Sbill /*
614280Sbill  * Reset state of driver if UBA reset was necessary.
615280Sbill  * Reset the csrl and lpr registers on open lines, and
616280Sbill  * restart transmitters.
617280Sbill  */
6182395Swnj dhreset(uban)
6192468Swnj 	int uban;
620280Sbill {
6212395Swnj 	register int dh, unit;
622280Sbill 	register struct tty *tp;
6232974Swnj 	register struct uba_device *ui;
6242421Skre 	int i;
625280Sbill 
6262395Swnj 	dh = 0;
6272643Swnj 	for (dh = 0; dh < NDH; dh++) {
6282421Skre 		ui = dhinfo[dh];
6292421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6302421Skre 			continue;
6312924Swnj 		printf(" dh%d", dh);
63230322Skarels 		if (dh_uballoc[uban] == dh) {
63330322Skarels 			int info;
63430322Skarels 
63530322Skarels 			info = uballoc(uban, (caddr_t)cfree,
63630322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
63730322Skarels 			if (info)
63830322Skarels 				cbase[uban] = UBAI_ADDR(info);
63930322Skarels 			else {
64030322Skarels 				printf(" [can't get uba map]");
64130322Skarels 				cbase[uban] = -1;
64230322Skarels 			}
64325433Skarels 		}
6442479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
64516190Skarels 		((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
6462421Skre 		unit = dh * 16;
6472421Skre 		for (i = 0; i < 16; i++) {
6482421Skre 			tp = &dh11[unit];
6495406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6502421Skre 				dhparam(unit);
6512479Swnj 				dmctl(unit, DML_ON, DMSET);
6525406Swnj 				tp->t_state &= ~TS_BUSY;
6532421Skre 				dhstart(tp);
6542421Skre 			}
6552421Skre 			unit++;
656300Sbill 		}
657300Sbill 	}
65816190Skarels 	dhsilos = 0;
659280Sbill }
6602395Swnj 
66116190Skarels int dhtransitions, dhslowtimers, dhfasttimers;		/*DEBUG*/
6622468Swnj /*
66316190Skarels  * At software clock interrupt time, check status.
66416190Skarels  * Empty all the dh silos that are in use, and decide whether
66516190Skarels  * to turn any silos off or on.
6662468Swnj  */
6672456Swnj dhtimer()
6682456Swnj {
66916190Skarels 	register int dh, s;
67016190Skarels 	static int timercalls;
6712456Swnj 
67216190Skarels 	if (dhsilos) {
67316190Skarels 		dhfasttimers++;		/*DEBUG*/
67416190Skarels 		timercalls++;
67516190Skarels 		s = spl5();
67616190Skarels 		for (dh = 0; dh < NDH; dh++)
67716190Skarels 			if (dhsilos & (1 << dh))
67816190Skarels 				dhrint(dh);
67916190Skarels 		splx(s);
68016190Skarels 	}
68116190Skarels 	if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
68216190Skarels 		dhslowtimers++;		/*DEBUG*/
68316190Skarels 		timercalls = 0;
68416190Skarels 		for (dh = 0; dh < NDH; dh++) {
68516190Skarels 		    ave(dhrate[dh], dhchars[dh], 8);
68616190Skarels 		    if ((dhchars[dh] > dhhighrate) &&
68716190Skarels 		      ((dhsilos & (1 << dh)) == 0)) {
68816190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
68916190Skarels 			    (dhchars[dh] > 500? 32 : 16);
69016190Skarels 			dhsilos |= (1 << dh);
69116190Skarels 			dhtransitions++;		/*DEBUG*/
69216190Skarels 		    } else if ((dhsilos & (1 << dh)) &&
69316190Skarels 		      (dhrate[dh] < dhlowrate)) {
69416190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
69516190Skarels 			dhsilos &= ~(1 << dh);
69616190Skarels 		    }
69716190Skarels 		    dhchars[dh] = 0;
69816190Skarels 		}
69916190Skarels 	}
70016190Skarels 	timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
7012456Swnj }
7022456Swnj 
7032468Swnj /*
7042479Swnj  * Turn on the line associated with dh dev.
7052468Swnj  */
706*39061Smarc dmopen(dev, flag)
7072468Swnj 	dev_t dev;
7082468Swnj {
7092468Swnj 	register struct tty *tp;
7102468Swnj 	register struct dmdevice *addr;
7112974Swnj 	register struct uba_device *ui;
7122468Swnj 	register int unit;
7132468Swnj 	register int dm;
7143792Swnj 	int s;
7152468Swnj 
7162468Swnj 	unit = minor(dev);
7172479Swnj 	dm = unit >> 4;
7182468Swnj 	tp = &dh11[unit];
7192566Swnj 	unit &= 0xf;
72016942Skarels 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
7215406Swnj 		tp->t_state |= TS_CARR_ON;
7222468Swnj 		return;
7232468Swnj 	}
7242468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7253792Swnj 	s = spl5();
72630341Skarels 	for (;;) {
72730341Skarels 		addr->dmcsr &= ~DM_SE;
72830341Skarels 		while (addr->dmcsr & DM_BUSY)
72930341Skarels 			;
73030341Skarels 		addr->dmcsr = unit;
73130341Skarels 		addr->dmlstat = DML_ON;
73230349Skarels 		if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit)))
73330341Skarels 			tp->t_state |= TS_CARR_ON;
73430341Skarels 		addr->dmcsr = DM_IE|DM_SE;
735*39061Smarc 		if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK ||
736*39061Smarc 		    tp->t_cflag&CLOCAL)
73730341Skarels 			break;
7382468Swnj 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
73930341Skarels 	}
7403792Swnj 	splx(s);
7412468Swnj }
7422468Swnj 
7432468Swnj /*
7442468Swnj  * Dump control bits into the DM registers.
7452468Swnj  */
7462468Swnj dmctl(dev, bits, how)
7472468Swnj 	dev_t dev;
7482468Swnj 	int bits, how;
7492468Swnj {
7502974Swnj 	register struct uba_device *ui;
7512468Swnj 	register struct dmdevice *addr;
7522468Swnj 	register int unit, s;
7532468Swnj 	int dm;
7542468Swnj 
7552468Swnj 	unit = minor(dev);
7562468Swnj 	dm = unit >> 4;
7572468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7582468Swnj 		return;
7592468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7602468Swnj 	s = spl5();
7612479Swnj 	addr->dmcsr &= ~DM_SE;
7622479Swnj 	while (addr->dmcsr & DM_BUSY)
7632468Swnj 		;
7642468Swnj 	addr->dmcsr = unit & 0xf;
7652468Swnj 	switch(how) {
7662468Swnj 	case DMSET:
7672468Swnj 		addr->dmlstat = bits;
7682468Swnj 		break;
7692468Swnj 	case DMBIS:
7702468Swnj 		addr->dmlstat |= bits;
7712468Swnj 		break;
7722468Swnj 	case DMBIC:
7732468Swnj 		addr->dmlstat &= ~bits;
7742468Swnj 		break;
7752468Swnj 	}
7763792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7772468Swnj 	splx(s);
7782468Swnj }
7792468Swnj 
7802468Swnj /*
7812468Swnj  * DM11 interrupt; deal with carrier transitions.
7822468Swnj  */
7832468Swnj dmintr(dm)
7842468Swnj 	register int dm;
7852468Swnj {
7862974Swnj 	register struct uba_device *ui;
7872468Swnj 	register struct tty *tp;
7882468Swnj 	register struct dmdevice *addr;
78916942Skarels 	int unit;
7902468Swnj 
7912468Swnj 	ui = dminfo[dm];
7922479Swnj 	if (ui == 0)
7932479Swnj 		return;
7942468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7953997Sroot 	if (addr->dmcsr&DM_DONE) {
7963997Sroot 		if (addr->dmcsr&DM_CF) {
79716942Skarels 			unit = addr->dmcsr & 0xf;
79816942Skarels 			tp = &dh11[(dm << 4) + unit];
79925394Skarels 			if (addr->dmlstat & DML_CAR)
80025394Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
80125394Skarels 			else if ((dhsoftCAR[dm] & (1<<unit)) == 0 &&
80225394Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
80325394Skarels 				addr->dmlstat = 0;
8043997Sroot 		}
8053997Sroot 		addr->dmcsr = DM_IE|DM_SE;
8062468Swnj 	}
8072468Swnj }
8082625Swnj #endif
809