xref: /csrg-svn/sys/vax/uba/dh.c (revision 40729)
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*40729Skarels  *	@(#)dh.c	7.11 (Berkeley) 04/03/90
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 "user.h"
2117122Sbloom #include "proc.h"
2217122Sbloom #include "ioctl.h"
2317122Sbloom #include "tty.h"
2417122Sbloom #include "map.h"
2517122Sbloom #include "buf.h"
2617122Sbloom #include "vm.h"
2717122Sbloom #include "kernel.h"
2818311Sralph #include "syslog.h"
298472Sroot 
3017122Sbloom #include "ubareg.h"
3117122Sbloom #include "ubavar.h"
3217122Sbloom #include "dhreg.h"
3317122Sbloom #include "dmreg.h"
348472Sroot 
3517122Sbloom #include "bkmac.h"
3617122Sbloom #include "clist.h"
3717122Sbloom #include "file.h"
3817122Sbloom #include "uio.h"
3913Sbill 
402468Swnj /*
412479Swnj  * Definition of the driver for the auto-configuration program.
422479Swnj  * There is one definition for the dh and one for the dm.
432468Swnj  */
4416190Skarels int	dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
452974Swnj struct	uba_device *dhinfo[NDH];
462395Swnj u_short	dhstd[] = { 0 };
472395Swnj struct	uba_driver dhdriver =
482605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
492395Swnj 
502605Swnj int	dmprobe(), dmattach(), dmintr();
512974Swnj struct	uba_device *dminfo[NDH];
522479Swnj u_short	dmstd[] = { 0 };
532479Swnj struct	uba_driver dmdriver =
542605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
5513Sbill 
566615Ssam #ifndef	PORTSELECTOR
5739061Smarc #define	ISPEED	TTYDEF_SPEED
5839061Smarc #define	LFLAG	TTYDEF_LFLAG
596615Ssam #else
606615Ssam #define	ISPEED	B4800
6139061Smarc #define	LFLAG	(TTYDEF_LFLAG&~ECHO)
626615Ssam #endif
636615Ssam 
6416190Skarels #define	FASTTIMER	(hz/30)		/* scan rate with silos on */
6516190Skarels 
6613Sbill /*
672479Swnj  * Local variables for the driver
6813Sbill  */
692643Swnj short	dhsar[NDH];			/* software copy of last bar */
702643Swnj short	dhsoftCAR[NDH];
7113Sbill 
722643Swnj struct	tty dh11[NDH*16];
732643Swnj int	ndh11	= NDH*16;
742479Swnj int	dhact;				/* mask of active dh's */
7516190Skarels int	dhsilos;			/* mask of dh's with silo in use */
7616190Skarels int	dhchars[NDH];			/* recent input count */
7716190Skarels int	dhrate[NDH];			/* smoothed input count */
7816190Skarels int	dhhighrate = 100;		/* silo on if dhchars > dhhighrate */
7916190Skarels int	dhlowrate = 75;			/* silo off if dhrate < dhlowrate */
8016190Skarels static short timerstarted;
812479Swnj int	dhstart(), ttrstrt();
8213Sbill 
8339061Smarc struct speedtab dhspeedtab[] = {
8439061Smarc 	19200,	14,
8539061Smarc 	9600,	13,
8639061Smarc 	4800,	12,
8739061Smarc 	2400,	11,
8839061Smarc 	1800,	10,
8939061Smarc 	1200,	9,
9039061Smarc 	600,	8,
9139061Smarc 	300,	7,
9239061Smarc 	200,	6,
9339061Smarc 	150,	5,
9439061Smarc 	134,	4,
9539061Smarc 	110,	3,
9639061Smarc 	75,	2,
9739061Smarc 	50,	1,
9839061Smarc 	0,	0,
9939061Smarc 	EXTA,	14,
10039061Smarc 	EXTB,	15,
10139061Smarc 	-1,	-1
10239061Smarc };
10339061Smarc 
1042479Swnj /*
10530322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
10630322Skarels  * The identity of the board which allocated resources is recorded,
10730322Skarels  * so the process may be repeated after UNIBUS resets.
1082479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1092479Swnj  * into an i/o space address for the DMA routine.
1102479Swnj  */
11130322Skarels int	dh_uballoc[NUBA];	/* which dh (if any) allocated unibus map */
11230322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
1132479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
11413Sbill 
1152456Swnj /*
1162456Swnj  * Routine for configuration to force a dh to interrupt.
1172456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1182456Swnj  */
1192468Swnj /*ARGSUSED*/
1202605Swnj dhprobe(reg)
1212395Swnj 	caddr_t reg;
1222395Swnj {
1232468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1242479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1252395Swnj 
1262605Swnj #ifdef lint
1272605Swnj 	br = 0; cvec = br; br = cvec;
1287384Sroot 	if (ndh11 == 0) ndh11 = 1;
1294932Swnj 	dhrint(0); dhxint(0);
1302605Swnj #endif
1312696Swnj #ifndef notdef
1322566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1336380Swnj 	DELAY(1000);
1347384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1352566Swnj 	dhaddr->un.dhcsr = 0;
1362566Swnj #else
1372456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1382456Swnj 	DELAY(5);
1392456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1402421Skre 	dhaddr->dhbcr = -1;
1412456Swnj 	dhaddr->dhcar = 0;
1422421Skre 	dhaddr->dhbar = 1;
1432456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1442421Skre 	dhaddr->un.dhcsr = 0;
1452456Swnj 	if (cvec && cvec != 0x200)
1462456Swnj 		cvec -= 4;		/* transmit -> receive */
1472482Swnj #endif
1487408Skre 	return (sizeof (struct dhdevice));
1492395Swnj }
1502395Swnj 
1512456Swnj /*
1522605Swnj  * Routine called to attach a dh.
1532456Swnj  */
1542605Swnj dhattach(ui)
1552974Swnj 	struct uba_device *ui;
1562395Swnj {
1572395Swnj 
1582566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
15926219Skarels 	cbase[ui->ui_ubanum] = -1;
16036610Sbostic 	dh_uballoc[ui->ui_ubanum] = -1;
1612395Swnj }
1622395Swnj 
16313Sbill /*
1642479Swnj  * Configuration routine to cause a dm to interrupt.
1652479Swnj  */
1662605Swnj dmprobe(reg)
1672605Swnj 	caddr_t reg;
1682479Swnj {
1692479Swnj 	register int br, vec;			/* value-result */
1702605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1712479Swnj 
1722605Swnj #ifdef lint
1733101Swnj 	br = 0; vec = br; br = vec;
1746185Ssam 	dmintr(0);
1752605Swnj #endif
1762479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1772479Swnj 	DELAY(20);
1782479Swnj 	dmaddr->dmcsr = 0;
1792605Swnj 	return (1);
1802479Swnj }
1812479Swnj 
1822605Swnj /*ARGSUSED*/
1832605Swnj dmattach(ui)
1842974Swnj 	struct uba_device *ui;
1852479Swnj {
1862479Swnj 
1872479Swnj 	/* no local state to set up */
1882479Swnj }
1892479Swnj 
1902479Swnj /*
1912468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1922468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1932468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
19413Sbill  */
19513Sbill /*ARGSUSED*/
19613Sbill dhopen(dev, flag)
1972395Swnj 	dev_t dev;
19813Sbill {
19913Sbill 	register struct tty *tp;
2002395Swnj 	register int unit, dh;
2012479Swnj 	register struct dhdevice *addr;
2022974Swnj 	register struct uba_device *ui;
203*40729Skarels 	int s, error;
20439061Smarc 	int dhparam();
20513Sbill 
2062395Swnj 	unit = minor(dev);
2072395Swnj 	dh = unit >> 4;
2088566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
2098566Sroot 		return (ENXIO);
2102395Swnj 	tp = &dh11[unit];
2118566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
2128566Sroot 		return (EBUSY);
2132479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
21413Sbill 	tp->t_addr = (caddr_t)addr;
21513Sbill 	tp->t_oproc = dhstart;
21639061Smarc 	tp->t_param = dhparam;
21739061Smarc 	tp->t_dev = dev;
2185406Swnj 	tp->t_state |= TS_WOPEN;
2192468Swnj 	/*
2202468Swnj 	 * While setting up state for this uba and this dh,
2212468Swnj 	 * block uba resets which can clear the state.
2222468Swnj 	 */
2232468Swnj 	s = spl5();
22426219Skarels 	if (cbase[ui->ui_ubanum] == -1) {
22530322Skarels 		dh_uballoc[ui->ui_ubanum] = dh;
22630322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22730322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22813Sbill 	}
22916190Skarels 	if (timerstarted == 0) {
23016190Skarels 		timerstarted++;
23116190Skarels 		timeout(dhtimer, (caddr_t) 0, hz);
23216190Skarels 	}
2332456Swnj 	if ((dhact&(1<<dh)) == 0) {
2342456Swnj 		addr->un.dhcsr |= DH_IE;
2352468Swnj 		dhact |= (1<<dh);
23616190Skarels 		addr->dhsilo = 0;
2372456Swnj 	}
23813Sbill 	splx(s);
2392468Swnj 	/*
24027049Skarels 	 * If this is first open, initialize tty state to default.
2412468Swnj 	 */
2425406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
24313Sbill 		ttychars(tp);
24427049Skarels #ifndef PORTSELECTOR
24527049Skarels 		if (tp->t_ispeed == 0) {
24639061Smarc #endif
24739061Smarc 			tp->t_iflag = TTYDEF_IFLAG;
24839061Smarc 			tp->t_oflag = TTYDEF_OFLAG;
24939061Smarc 			tp->t_cflag = TTYDEF_CFLAG;
25039061Smarc 			tp->t_lflag = LFLAG;
25139061Smarc 			tp->t_ispeed = tp->t_ospeed = ISPEED;
25239061Smarc #ifdef PORTSELECTOR
25339061Smarc 			tp->t_cflag |= HUPCL;
25427049Skarels #else
25527049Skarels 		}
25639061Smarc #endif
25739061Smarc 		dhparam(tp, &tp->t_termios);
25839061Smarc 		ttsetwater(tp);
25913Sbill 	}
2602468Swnj 	/*
2612468Swnj 	 * Wait for carrier, then process line discipline specific open.
2622468Swnj 	 */
263*40729Skarels 	if (error = dmopen(dev, flag))
264*40729Skarels 		return (error);
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));
28339061Smarc 	if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0)
2842479Swnj 		dmctl(unit, DML_OFF, DMSET);
285*40729Skarels 	return (ttyclose(tp));
28613Sbill }
28713Sbill 
28839061Smarc dhread(dev, uio, flag)
2892395Swnj 	dev_t dev;
2907725Sroot 	struct uio *uio;
29113Sbill {
2928490Sroot 	register struct tty *tp = &dh11[minor(dev)];
29313Sbill 
29439061Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
29513Sbill }
29613Sbill 
29739061Smarc dhwrite(dev, uio, flag)
2982395Swnj 	dev_t dev;
2997831Sroot 	struct uio *uio;
30013Sbill {
3018490Sroot 	register struct tty *tp = &dh11[minor(dev)];
30213Sbill 
30339061Smarc 	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;
31339061Smarc 	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 		}
33839061Smarc 		cc = c&0xff;
33939061Smarc 		if (c&DH_PE)
34039061Smarc 			cc |= TTY_PE;
34139061Smarc 		if ((c&DH_DO) && overrun == 0) {
34224840Seric 			log(LOG_WARNING, "dh%d: silo overflow\n", dh);
3432924Swnj 			overrun = 1;
3442924Swnj 		}
34539061Smarc 		if (c&DH_FE)
34639061Smarc 			cc |= TTY_FE;
34739061Smarc 		(*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);
36739061Smarc 	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  */
39739061Smarc dhparam(tp, t)
39839061Smarc 	register struct tty *tp;
39939061Smarc 	register struct termios *t;
40013Sbill {
4012479Swnj 	register struct dhdevice *addr;
4022395Swnj 	register int lpar;
40339061Smarc 	register int cflag = t->c_cflag;
40439061Smarc 	int unit = minor(tp->t_dev);
405300Sbill 	int s;
40639061Smarc 	int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab);
40739061Smarc 	int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab);
40813Sbill 
40939061Smarc 	/* check requested parameters */
41039061Smarc 	if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
41139061Smarc 		return(EINVAL);
41239061Smarc 	if (ispeed == 0)
41339061Smarc 		ispeed = ospeed;
41439061Smarc 	/* and copy to tty */
41539061Smarc 	tp->t_ispeed = t->c_ispeed;
41639061Smarc 	tp->t_ospeed = t->c_ospeed;
41739061Smarc 	tp->t_cflag = cflag;
4182468Swnj 	/*
4192468Swnj 	 * Block interrupts so parameters will be set
4202468Swnj 	 * before the line interrupts.
4212468Swnj 	 */
42239061Smarc 	addr = (struct dhdevice *)tp->t_addr;
423300Sbill 	s = spl5();
4242468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
42539061Smarc 	if (ospeed == 0) {
42639061Smarc 		tp->t_cflag |= HUPCL;
4272479Swnj 		dmctl(unit, DML_OFF, DMSET);
42828147Skarels 		splx(s);
42939061Smarc 		return 0;
43013Sbill 	}
43139061Smarc 	lpar = (ospeed<<10) | (ispeed<<6);
43239061Smarc 	switch (cflag&CSIZE) {
43339061Smarc 	case CS6:	lpar |= BITS6; break;
43439061Smarc 	case CS7:	lpar |= BITS7; break;
43539061Smarc 	case CS8:	lpar |= BITS8; break;
43639061Smarc 	}
43739061Smarc 	if (cflag&PARENB)
43839061Smarc 		lpar |= PENABLE;
43939061Smarc 	if (cflag&PARODD)
4402395Swnj 		lpar |= OPAR;
44139061Smarc 	if (cflag&CSTOPB)
4422395Swnj 		lpar |= TWOSB;
4432395Swnj 	addr->dhlpr = lpar;
444300Sbill 	splx(s);
44539061Smarc 	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 	 */
52839061Smarc 	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;
54539061Smarc 	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  */
70639061Smarc 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;
714*40729Skarels 	int s, error = 0;
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;
722*40729Skarels 		return (0);
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;
73539061Smarc 		if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK ||
73639061Smarc 		    tp->t_cflag&CLOCAL)
73730341Skarels 			break;
738*40729Skarels 		if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
739*40729Skarels 		    ttopen, 0))
740*40729Skarels 			break;
74130341Skarels 	}
7423792Swnj 	splx(s);
743*40729Skarels 	return (error);
7442468Swnj }
7452468Swnj 
7462468Swnj /*
7472468Swnj  * Dump control bits into the DM registers.
7482468Swnj  */
7492468Swnj dmctl(dev, bits, how)
7502468Swnj 	dev_t dev;
7512468Swnj 	int bits, how;
7522468Swnj {
7532974Swnj 	register struct uba_device *ui;
7542468Swnj 	register struct dmdevice *addr;
7552468Swnj 	register int unit, s;
7562468Swnj 	int dm;
7572468Swnj 
7582468Swnj 	unit = minor(dev);
7592468Swnj 	dm = unit >> 4;
7602468Swnj 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
7612468Swnj 		return;
7622468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7632468Swnj 	s = spl5();
7642479Swnj 	addr->dmcsr &= ~DM_SE;
7652479Swnj 	while (addr->dmcsr & DM_BUSY)
7662468Swnj 		;
7672468Swnj 	addr->dmcsr = unit & 0xf;
7682468Swnj 	switch(how) {
7692468Swnj 	case DMSET:
7702468Swnj 		addr->dmlstat = bits;
7712468Swnj 		break;
7722468Swnj 	case DMBIS:
7732468Swnj 		addr->dmlstat |= bits;
7742468Swnj 		break;
7752468Swnj 	case DMBIC:
7762468Swnj 		addr->dmlstat &= ~bits;
7772468Swnj 		break;
7782468Swnj 	}
7793792Swnj 	addr->dmcsr = DM_IE|DM_SE;
7802468Swnj 	splx(s);
7812468Swnj }
7822468Swnj 
7832468Swnj /*
7842468Swnj  * DM11 interrupt; deal with carrier transitions.
7852468Swnj  */
7862468Swnj dmintr(dm)
7872468Swnj 	register int dm;
7882468Swnj {
7892974Swnj 	register struct uba_device *ui;
7902468Swnj 	register struct tty *tp;
7912468Swnj 	register struct dmdevice *addr;
79216942Skarels 	int unit;
7932468Swnj 
7942468Swnj 	ui = dminfo[dm];
7952479Swnj 	if (ui == 0)
7962479Swnj 		return;
7972468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7983997Sroot 	if (addr->dmcsr&DM_DONE) {
7993997Sroot 		if (addr->dmcsr&DM_CF) {
80016942Skarels 			unit = addr->dmcsr & 0xf;
80116942Skarels 			tp = &dh11[(dm << 4) + unit];
80225394Skarels 			if (addr->dmlstat & DML_CAR)
80325394Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
80425394Skarels 			else if ((dhsoftCAR[dm] & (1<<unit)) == 0 &&
80525394Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
80625394Skarels 				addr->dmlstat = 0;
8073997Sroot 		}
8083997Sroot 		addr->dmcsr = DM_IE|DM_SE;
8092468Swnj 	}
8102468Swnj }
8112625Swnj #endif
812