xref: /csrg-svn/sys/vax/uba/dh.c (revision 49759)
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*49759Smarc  *	@(#)dh.c	7.17 (Berkeley) 05/16/91
723320Smckusick  */
813Sbill 
91934Swnj #include "dh.h"
102643Swnj #if NDH > 0
1113Sbill /*
122479Swnj  * DH-11/DM-11 driver
1313Sbill  */
1445804Sbostic #include "../include/pte.h"
159771Ssam 
1645804Sbostic #include "sys/param.h"
1716062Skarels #include "uba.h"
1845804Sbostic #include "sys/conf.h"
1945804Sbostic #include "sys/user.h"
2045804Sbostic #include "sys/proc.h"
2145804Sbostic #include "sys/ioctl.h"
2245804Sbostic #include "sys/tty.h"
2345804Sbostic #include "sys/map.h"
2445804Sbostic #include "sys/buf.h"
2545804Sbostic #include "sys/vm.h"
2645804Sbostic #include "sys/kernel.h"
2745804Sbostic #include "sys/syslog.h"
288472Sroot 
2917122Sbloom #include "ubareg.h"
3017122Sbloom #include "ubavar.h"
3117122Sbloom #include "dhreg.h"
3217122Sbloom #include "dmreg.h"
338472Sroot 
3445804Sbostic #include "sys/clist.h"
3545804Sbostic #include "sys/file.h"
3645804Sbostic #include "sys/uio.h"
3713Sbill 
382468Swnj /*
392479Swnj  * Definition of the driver for the auto-configuration program.
402479Swnj  * There is one definition for the dh and one for the dm.
412468Swnj  */
4216190Skarels int	dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
432974Swnj struct	uba_device *dhinfo[NDH];
442395Swnj u_short	dhstd[] = { 0 };
452395Swnj struct	uba_driver dhdriver =
462605Swnj 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
472395Swnj 
482605Swnj int	dmprobe(), dmattach(), dmintr();
492974Swnj struct	uba_device *dminfo[NDH];
502479Swnj u_short	dmstd[] = { 0 };
512479Swnj struct	uba_driver dmdriver =
522605Swnj 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
5313Sbill 
546615Ssam #ifndef	PORTSELECTOR
5539061Smarc #define	ISPEED	TTYDEF_SPEED
5639061Smarc #define	LFLAG	TTYDEF_LFLAG
576615Ssam #else
586615Ssam #define	ISPEED	B4800
5939061Smarc #define	LFLAG	(TTYDEF_LFLAG&~ECHO)
606615Ssam #endif
616615Ssam 
6216190Skarels #define	FASTTIMER	(hz/30)		/* scan rate with silos on */
6316190Skarels 
6413Sbill /*
652479Swnj  * Local variables for the driver
6613Sbill  */
672643Swnj short	dhsar[NDH];			/* software copy of last bar */
682643Swnj short	dhsoftCAR[NDH];
6913Sbill 
702643Swnj struct	tty dh11[NDH*16];
712643Swnj int	ndh11	= NDH*16;
722479Swnj int	dhact;				/* mask of active dh's */
7316190Skarels int	dhsilos;			/* mask of dh's with silo in use */
7416190Skarels int	dhchars[NDH];			/* recent input count */
7516190Skarels int	dhrate[NDH];			/* smoothed input count */
7616190Skarels int	dhhighrate = 100;		/* silo on if dhchars > dhhighrate */
7716190Skarels int	dhlowrate = 75;			/* silo off if dhrate < dhlowrate */
7816190Skarels static short timerstarted;
792479Swnj int	dhstart(), ttrstrt();
8013Sbill 
8139061Smarc struct speedtab dhspeedtab[] = {
8239061Smarc 	19200,	14,
8339061Smarc 	9600,	13,
8439061Smarc 	4800,	12,
8539061Smarc 	2400,	11,
8639061Smarc 	1800,	10,
8739061Smarc 	1200,	9,
8839061Smarc 	600,	8,
8939061Smarc 	300,	7,
9039061Smarc 	200,	6,
9139061Smarc 	150,	5,
9239061Smarc 	134,	4,
9339061Smarc 	110,	3,
9439061Smarc 	75,	2,
9539061Smarc 	50,	1,
9639061Smarc 	0,	0,
9739061Smarc 	EXTA,	14,
9839061Smarc 	EXTB,	15,
9939061Smarc 	-1,	-1
10039061Smarc };
10139061Smarc 
1022479Swnj /*
10330322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
10430322Skarels  * The identity of the board which allocated resources is recorded,
10530322Skarels  * so the process may be repeated after UNIBUS resets.
1062479Swnj  * The UBACVT macro converts a clist space address for unibus uban
1072479Swnj  * into an i/o space address for the DMA routine.
1082479Swnj  */
10930322Skarels int	dh_uballoc[NUBA];	/* which dh (if any) allocated unibus map */
11030322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
1112479Swnj #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
11213Sbill 
1132456Swnj /*
1142456Swnj  * Routine for configuration to force a dh to interrupt.
1152456Swnj  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
1162456Swnj  */
1172468Swnj /*ARGSUSED*/
dhprobe(reg)1182605Swnj dhprobe(reg)
1192395Swnj 	caddr_t reg;
1202395Swnj {
1212468Swnj 	register int br, cvec;		/* these are ``value-result'' */
1222479Swnj 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
1232395Swnj 
1242605Swnj #ifdef lint
1252605Swnj 	br = 0; cvec = br; br = cvec;
1267384Sroot 	if (ndh11 == 0) ndh11 = 1;
1274932Swnj 	dhrint(0); dhxint(0);
1282605Swnj #endif
1292696Swnj #ifndef notdef
1302566Swnj 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
1316380Swnj 	DELAY(1000);
1327384Sroot 	dhaddr->un.dhcsr &= ~DH_RI;
1332566Swnj 	dhaddr->un.dhcsr = 0;
1342566Swnj #else
1352456Swnj 	dhaddr->un.dhcsr = DH_TIE;
1362456Swnj 	DELAY(5);
1372456Swnj 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
1382421Skre 	dhaddr->dhbcr = -1;
1392456Swnj 	dhaddr->dhcar = 0;
1402421Skre 	dhaddr->dhbar = 1;
1412456Swnj 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
1422421Skre 	dhaddr->un.dhcsr = 0;
1432456Swnj 	if (cvec && cvec != 0x200)
1442456Swnj 		cvec -= 4;		/* transmit -> receive */
1452482Swnj #endif
1467408Skre 	return (sizeof (struct dhdevice));
1472395Swnj }
1482395Swnj 
1492456Swnj /*
1502605Swnj  * Routine called to attach a dh.
1512456Swnj  */
1522605Swnj dhattach(ui)
1532974Swnj 	struct uba_device *ui;
1542395Swnj {
1552395Swnj 
1562566Swnj 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
15726219Skarels 	cbase[ui->ui_ubanum] = -1;
15836610Sbostic 	dh_uballoc[ui->ui_ubanum] = -1;
1592395Swnj }
1602395Swnj 
16113Sbill /*
1622479Swnj  * Configuration routine to cause a dm to interrupt.
1632479Swnj  */
dmprobe(reg)1642605Swnj dmprobe(reg)
1652605Swnj 	caddr_t reg;
1662479Swnj {
1672479Swnj 	register int br, vec;			/* value-result */
1682605Swnj 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
1692479Swnj 
1702605Swnj #ifdef lint
1713101Swnj 	br = 0; vec = br; br = vec;
1726185Ssam 	dmintr(0);
1732605Swnj #endif
1742479Swnj 	dmaddr->dmcsr = DM_DONE|DM_IE;
1752479Swnj 	DELAY(20);
1762479Swnj 	dmaddr->dmcsr = 0;
1772605Swnj 	return (1);
1782479Swnj }
1792479Swnj 
1802605Swnj /*ARGSUSED*/
1812605Swnj dmattach(ui)
1822974Swnj 	struct uba_device *ui;
1832479Swnj {
1842479Swnj 
1852479Swnj 	/* no local state to set up */
1862479Swnj }
1872479Swnj 
1882479Swnj /*
1892468Swnj  * Open a DH11 line, mapping the clist onto the uba if this
1902468Swnj  * is the first dh on this uba.  Turn on this dh if this is
1912468Swnj  * the first use of it.  Also do a dmopen to wait for carrier.
19213Sbill  */
19313Sbill /*ARGSUSED*/
dhopen(dev,flag)19413Sbill dhopen(dev, flag)
1952395Swnj 	dev_t dev;
19613Sbill {
19713Sbill 	register struct tty *tp;
1982395Swnj 	register int unit, dh;
1992479Swnj 	register struct dhdevice *addr;
2002974Swnj 	register struct uba_device *ui;
20140729Skarels 	int s, error;
20239061Smarc 	int dhparam();
20313Sbill 
2042395Swnj 	unit = minor(dev);
2052395Swnj 	dh = unit >> 4;
2068566Sroot 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
2078566Sroot 		return (ENXIO);
2082395Swnj 	tp = &dh11[unit];
2098566Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
2108566Sroot 		return (EBUSY);
2112479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
21213Sbill 	tp->t_addr = (caddr_t)addr;
21313Sbill 	tp->t_oproc = dhstart;
21439061Smarc 	tp->t_param = dhparam;
21539061Smarc 	tp->t_dev = dev;
2162468Swnj 	/*
2172468Swnj 	 * While setting up state for this uba and this dh,
2182468Swnj 	 * block uba resets which can clear the state.
2192468Swnj 	 */
2202468Swnj 	s = spl5();
22126219Skarels 	if (cbase[ui->ui_ubanum] == -1) {
22230322Skarels 		dh_uballoc[ui->ui_ubanum] = dh;
22330322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22430322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22513Sbill 	}
22616190Skarels 	if (timerstarted == 0) {
22716190Skarels 		timerstarted++;
22816190Skarels 		timeout(dhtimer, (caddr_t) 0, hz);
22916190Skarels 	}
2302456Swnj 	if ((dhact&(1<<dh)) == 0) {
2312456Swnj 		addr->un.dhcsr |= DH_IE;
2322468Swnj 		dhact |= (1<<dh);
23316190Skarels 		addr->dhsilo = 0;
2342456Swnj 	}
23513Sbill 	splx(s);
2362468Swnj 	/*
23727049Skarels 	 * If this is first open, initialize tty state to default.
2382468Swnj 	 */
2395406Swnj 	if ((tp->t_state&TS_ISOPEN) == 0) {
24044393Smarc 		tp->t_state |= TS_WOPEN;
24113Sbill 		ttychars(tp);
24227049Skarels #ifndef PORTSELECTOR
24327049Skarels 		if (tp->t_ispeed == 0) {
24439061Smarc #endif
24539061Smarc 			tp->t_iflag = TTYDEF_IFLAG;
24639061Smarc 			tp->t_oflag = TTYDEF_OFLAG;
24739061Smarc 			tp->t_cflag = TTYDEF_CFLAG;
24839061Smarc 			tp->t_lflag = LFLAG;
24939061Smarc 			tp->t_ispeed = tp->t_ospeed = ISPEED;
25039061Smarc #ifdef PORTSELECTOR
25139061Smarc 			tp->t_cflag |= HUPCL;
25227049Skarels #else
25327049Skarels 		}
25439061Smarc #endif
25539061Smarc 		dhparam(tp, &tp->t_termios);
25639061Smarc 		ttsetwater(tp);
25713Sbill 	}
2582468Swnj 	/*
2592468Swnj 	 * Wait for carrier, then process line discipline specific open.
2602468Swnj 	 */
26140729Skarels 	if (error = dmopen(dev, flag))
26240729Skarels 		return (error);
2638566Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
26413Sbill }
26513Sbill 
26613Sbill /*
2672468Swnj  * Close a DH11 line, turning off the DM11.
26813Sbill  */
26913Sbill /*ARGSUSED*/
dhclose(dev,flag,mode,p)270*49759Smarc dhclose(dev, flag, mode, p)
2712395Swnj 	dev_t dev;
272*49759Smarc 	int flag, mode;
273*49759Smarc 	struct proc *p;
27413Sbill {
27513Sbill 	register struct tty *tp;
2762395Swnj 	register unit;
27713Sbill 
2782395Swnj 	unit = minor(dev);
2792395Swnj 	tp = &dh11[unit];
280*49759Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
2812479Swnj 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
28239061Smarc 	if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0)
2832479Swnj 		dmctl(unit, DML_OFF, DMSET);
28440729Skarels 	return (ttyclose(tp));
28513Sbill }
28613Sbill 
dhread(dev,uio,flag)28739061Smarc dhread(dev, uio, flag)
2882395Swnj 	dev_t dev;
2897725Sroot 	struct uio *uio;
29013Sbill {
2918490Sroot 	register struct tty *tp = &dh11[minor(dev)];
29213Sbill 
29339061Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
29413Sbill }
29513Sbill 
dhwrite(dev,uio,flag)29639061Smarc dhwrite(dev, uio, flag)
2972395Swnj 	dev_t dev;
2987831Sroot 	struct uio *uio;
29913Sbill {
3008490Sroot 	register struct tty *tp = &dh11[minor(dev)];
30113Sbill 
30239061Smarc 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
30313Sbill }
30413Sbill 
30513Sbill /*
30613Sbill  * DH11 receiver interrupt.
30713Sbill  */
dhrint(dh)3082395Swnj dhrint(dh)
3092395Swnj 	int dh;
31013Sbill {
31113Sbill 	register struct tty *tp;
31239061Smarc 	register c, cc;
3132479Swnj 	register struct dhdevice *addr;
314117Sbill 	register struct tty *tp0;
3152974Swnj 	register struct uba_device *ui;
3162924Swnj 	int overrun = 0;
31713Sbill 
3182395Swnj 	ui = dhinfo[dh];
3192479Swnj 	if (ui == 0 || ui->ui_alive == 0)
3202479Swnj 		return;
3212479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
3222468Swnj 	tp0 = &dh11[dh<<4];
3232468Swnj 	/*
3242468Swnj 	 * Loop fetching characters from the silo for this
3252468Swnj 	 * dh until there are no more in the silo.
3262468Swnj 	 */
3272468Swnj 	while ((c = addr->dhrcr) < 0) {
3282468Swnj 		tp = tp0 + ((c>>8)&0xf);
32916190Skarels 		dhchars[dh]++;
3305406Swnj 		if ((tp->t_state&TS_ISOPEN)==0) {
33125394Skarels 			wakeup((caddr_t)&tp->t_rawq);
33225394Skarels #ifdef PORTSELECTOR
33325394Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
3346615Ssam #endif
33525394Skarels 				continue;
33613Sbill 		}
33739061Smarc 		cc = c&0xff;
33839061Smarc 		if (c&DH_PE)
33939061Smarc 			cc |= TTY_PE;
34039061Smarc 		if ((c&DH_DO) && overrun == 0) {
34124840Seric 			log(LOG_WARNING, "dh%d: silo overflow\n", dh);
3422924Swnj 			overrun = 1;
3432924Swnj 		}
34439061Smarc 		if (c&DH_FE)
34539061Smarc 			cc |= TTY_FE;
34639061Smarc 		(*linesw[tp->t_line].l_rint)(cc, tp);
34713Sbill 	}
34813Sbill }
34913Sbill 
35013Sbill /*
3512468Swnj  * Ioctl for DH11.
35213Sbill  */
35313Sbill /*ARGSUSED*/
dhioctl(dev,cmd,data,flag)3547629Ssam dhioctl(dev, cmd, data, flag)
3557629Ssam 	caddr_t data;
35613Sbill {
35713Sbill 	register struct tty *tp;
3588566Sroot 	register int unit = minor(dev);
3598566Sroot 	int error;
36013Sbill 
3612395Swnj 	tp = &dh11[unit];
3628566Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3638566Sroot 	if (error >= 0)
3648566Sroot 		return (error);
3658566Sroot 	error = ttioctl(tp, cmd, data, flag);
36639061Smarc 	if (error >= 0)
3678566Sroot 		return (error);
3688566Sroot 	switch (cmd) {
3697629Ssam 
370168Sbill 	case TIOCSBRK:
3712479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
372168Sbill 		break;
3737629Ssam 
374168Sbill 	case TIOCCBRK:
3752479Swnj 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
376168Sbill 		break;
3777629Ssam 
378168Sbill 	case TIOCSDTR:
3792479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
380168Sbill 		break;
3817629Ssam 
382168Sbill 	case TIOCCDTR:
3832479Swnj 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
384168Sbill 		break;
3857629Ssam 
386168Sbill 	default:
3878566Sroot 		return (ENOTTY);
388168Sbill 	}
3898566Sroot 	return (0);
39013Sbill }
39113Sbill 
39213Sbill /*
39313Sbill  * Set parameters from open or stty into the DH hardware
39413Sbill  * registers.
39513Sbill  */
dhparam(tp,t)39639061Smarc dhparam(tp, t)
39739061Smarc 	register struct tty *tp;
39839061Smarc 	register struct termios *t;
39913Sbill {
4002479Swnj 	register struct dhdevice *addr;
4012395Swnj 	register int lpar;
40239061Smarc 	register int cflag = t->c_cflag;
40339061Smarc 	int unit = minor(tp->t_dev);
404300Sbill 	int s;
40539061Smarc 	int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab);
40639061Smarc 	int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab);
40713Sbill 
40839061Smarc 	/* check requested parameters */
40939061Smarc 	if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
41039061Smarc 		return(EINVAL);
41139061Smarc 	if (ispeed == 0)
41239061Smarc 		ispeed = ospeed;
41339061Smarc 	/* and copy to tty */
41439061Smarc 	tp->t_ispeed = t->c_ispeed;
41539061Smarc 	tp->t_ospeed = t->c_ospeed;
41639061Smarc 	tp->t_cflag = cflag;
4172468Swnj 	/*
4182468Swnj 	 * Block interrupts so parameters will be set
4192468Swnj 	 * before the line interrupts.
4202468Swnj 	 */
42139061Smarc 	addr = (struct dhdevice *)tp->t_addr;
422300Sbill 	s = spl5();
4232468Swnj 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
42439061Smarc 	if (ospeed == 0) {
42539061Smarc 		tp->t_cflag |= HUPCL;
4262479Swnj 		dmctl(unit, DML_OFF, DMSET);
42728147Skarels 		splx(s);
42839061Smarc 		return 0;
42913Sbill 	}
43039061Smarc 	lpar = (ospeed<<10) | (ispeed<<6);
43139061Smarc 	switch (cflag&CSIZE) {
43239061Smarc 	case CS6:	lpar |= BITS6; break;
43339061Smarc 	case CS7:	lpar |= BITS7; break;
43439061Smarc 	case CS8:	lpar |= BITS8; break;
43539061Smarc 	}
43639061Smarc 	if (cflag&PARENB)
43739061Smarc 		lpar |= PENABLE;
43839061Smarc 	if (cflag&PARODD)
4392395Swnj 		lpar |= OPAR;
44039061Smarc 	if (cflag&CSTOPB)
4412395Swnj 		lpar |= TWOSB;
4422395Swnj 	addr->dhlpr = lpar;
443300Sbill 	splx(s);
44439061Smarc 	return 0;
44513Sbill }
44613Sbill 
44713Sbill /*
44813Sbill  * DH11 transmitter interrupt.
44913Sbill  * Restart each line which used to be active but has
45013Sbill  * terminated transmission since the last interrupt.
45113Sbill  */
dhxint(dh)4522395Swnj dhxint(dh)
4532395Swnj 	int dh;
45413Sbill {
45513Sbill 	register struct tty *tp;
4562479Swnj 	register struct dhdevice *addr;
45713Sbill 	short ttybit, bar, *sbar;
4582974Swnj 	register struct uba_device *ui;
4592468Swnj 	register int unit;
4602605Swnj 	u_short cntr;
46113Sbill 
4622395Swnj 	ui = dhinfo[dh];
4632479Swnj 	addr = (struct dhdevice *)ui->ui_addr;
4642456Swnj 	if (addr->un.dhcsr & DH_NXM) {
4652456Swnj 		addr->un.dhcsr |= DH_CNI;
4662924Swnj 		printf("dh%d: NXM\n", dh);
467105Sbill 	}
4682395Swnj 	sbar = &dhsar[dh];
46913Sbill 	bar = *sbar & ~addr->dhbar;
4702395Swnj 	unit = dh * 16; ttybit = 1;
4712468Swnj 	addr->un.dhcsr &= (short)~DH_TI;
4722468Swnj 	for (; bar; unit++, ttybit <<= 1) {
4732468Swnj 		if (bar & ttybit) {
47413Sbill 			*sbar &= ~ttybit;
47513Sbill 			bar &= ~ttybit;
4762395Swnj 			tp = &dh11[unit];
4775406Swnj 			tp->t_state &= ~TS_BUSY;
4785406Swnj 			if (tp->t_state&TS_FLUSH)
4795406Swnj 				tp->t_state &= ~TS_FLUSH;
480113Sbill 			else {
4812456Swnj 				addr->un.dhcsrl = (unit&017)|DH_IE;
4822468Swnj 				/*
4832468Swnj 				 * Do arithmetic in a short to make up
4842468Swnj 				 * for lost 16&17 bits.
4852468Swnj 				 */
4862605Swnj 				cntr = addr->dhcar -
4872468Swnj 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4883101Swnj 				ndflush(&tp->t_outq, (int)cntr);
489113Sbill 			}
490113Sbill 			if (tp->t_line)
49113Sbill 				(*linesw[tp->t_line].l_start)(tp);
492113Sbill 			else
49313Sbill 				dhstart(tp);
49413Sbill 		}
49513Sbill 	}
49613Sbill }
49713Sbill 
49813Sbill /*
49913Sbill  * Start (restart) transmission on the given DH11 line.
50013Sbill  */
dhstart(tp)50113Sbill dhstart(tp)
5022395Swnj 	register struct tty *tp;
50313Sbill {
5042479Swnj 	register struct dhdevice *addr;
5052468Swnj 	register int car, dh, unit, nch;
5062395Swnj 	int s;
50713Sbill 
5082468Swnj 	unit = minor(tp->t_dev);
5092468Swnj 	dh = unit >> 4;
5102468Swnj 	unit &= 0xf;
5112479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5122468Swnj 
51313Sbill 	/*
5142468Swnj 	 * Must hold interrupts in following code to prevent
5152468Swnj 	 * state of the tp from changing.
51613Sbill 	 */
51713Sbill 	s = spl5();
5182468Swnj 	/*
5192468Swnj 	 * If it's currently active, or delaying, no need to do anything.
5202468Swnj 	 */
5215406Swnj 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
52213Sbill 		goto out;
5232468Swnj 	/*
5242468Swnj 	 * If there are sleepers, and output has drained below low
5252468Swnj 	 * water mark, wake up the sleepers.
5262468Swnj 	 */
52739061Smarc 	if (tp->t_outq.c_cc<=tp->t_lowat) {
5285406Swnj 		if (tp->t_state&TS_ASLEEP) {
5295406Swnj 			tp->t_state &= ~TS_ASLEEP;
5305406Swnj 			wakeup((caddr_t)&tp->t_outq);
5315406Swnj 		}
5325406Swnj 		if (tp->t_wsel) {
5335406Swnj 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
5345406Swnj 			tp->t_wsel = 0;
5355406Swnj 			tp->t_state &= ~TS_WCOLL;
5365406Swnj 		}
53713Sbill 	}
5382468Swnj 	/*
5392468Swnj 	 * Now restart transmission unless the output queue is
5402468Swnj 	 * empty.
5412468Swnj 	 */
54213Sbill 	if (tp->t_outq.c_cc == 0)
54313Sbill 		goto out;
54439061Smarc 	if (1 || !(tp->t_oflag&OPOST))	/*XXX*/
54513Sbill 		nch = ndqb(&tp->t_outq, 0);
5462395Swnj 	else {
54713Sbill 		nch = ndqb(&tp->t_outq, 0200);
5482468Swnj 		/*
5492468Swnj 		 * If first thing on queue is a delay process it.
5502468Swnj 		 */
55113Sbill 		if (nch == 0) {
55213Sbill 			nch = getc(&tp->t_outq);
5532468Swnj 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5545406Swnj 			tp->t_state |= TS_TIMEOUT;
55513Sbill 			goto out;
55613Sbill 		}
55713Sbill 	}
5582468Swnj 	/*
5592468Swnj 	 * If characters to transmit, restart transmission.
5602468Swnj 	 */
56113Sbill 	if (nch) {
5622468Swnj 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
5632468Swnj 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
5643586Sroot 		/*
5653586Sroot 		 * The following nonsense with short word
5663586Sroot 		 * is to make sure the dhbar |= word below
5673586Sroot 		 * is done with an interlocking bisw2 instruction.
5683586Sroot 		 */
5693586Sroot 		{ short word = 1 << unit;
5703586Sroot 		dhsar[dh] |= word;
5712468Swnj 		addr->dhcar = car;
57213Sbill 		addr->dhbcr = -nch;
5733586Sroot 		addr->dhbar |= word;
5743586Sroot 		}
5755406Swnj 		tp->t_state |= TS_BUSY;
57613Sbill 	}
5772395Swnj out:
57813Sbill 	splx(s);
57913Sbill }
58013Sbill 
58113Sbill /*
5822468Swnj  * Stop output on a line, e.g. for ^S/^Q or output flush.
58313Sbill  */
58413Sbill /*ARGSUSED*/
dhstop(tp,flag)58513Sbill dhstop(tp, flag)
5862468Swnj 	register struct tty *tp;
58713Sbill {
5882479Swnj 	register struct dhdevice *addr;
5892395Swnj 	register int unit, s;
59013Sbill 
5912479Swnj 	addr = (struct dhdevice *)tp->t_addr;
5922468Swnj 	/*
5932468Swnj 	 * Block input/output interrupts while messing with state.
5942468Swnj 	 */
5952468Swnj 	s = spl5();
5965406Swnj 	if (tp->t_state & TS_BUSY) {
5972468Swnj 		/*
5982468Swnj 		 * Device is transmitting; stop output
5992468Swnj 		 * by selecting the line and setting the byte
6002468Swnj 		 * count to -1.  We will clean up later
6012468Swnj 		 * by examining the address where the dh stopped.
6022468Swnj 		 */
6032395Swnj 		unit = minor(tp->t_dev);
6042456Swnj 		addr->un.dhcsrl = (unit&017) | DH_IE;
6055406Swnj 		if ((tp->t_state&TS_TTSTOP)==0)
6065406Swnj 			tp->t_state |= TS_FLUSH;
607113Sbill 		addr->dhbcr = -1;
608113Sbill 	}
60913Sbill 	splx(s);
61013Sbill }
61113Sbill 
612168Sbill /*
613280Sbill  * Reset state of driver if UBA reset was necessary.
614280Sbill  * Reset the csrl and lpr registers on open lines, and
615280Sbill  * restart transmitters.
616280Sbill  */
dhreset(uban)6172395Swnj dhreset(uban)
6182468Swnj 	int uban;
619280Sbill {
6202395Swnj 	register int dh, unit;
621280Sbill 	register struct tty *tp;
6222974Swnj 	register struct uba_device *ui;
6232421Skre 	int i;
624280Sbill 
6252395Swnj 	dh = 0;
6262643Swnj 	for (dh = 0; dh < NDH; dh++) {
6272421Skre 		ui = dhinfo[dh];
6282421Skre 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6292421Skre 			continue;
6302924Swnj 		printf(" dh%d", dh);
63130322Skarels 		if (dh_uballoc[uban] == dh) {
63230322Skarels 			int info;
63330322Skarels 
63430322Skarels 			info = uballoc(uban, (caddr_t)cfree,
63530322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
63630322Skarels 			if (info)
63730322Skarels 				cbase[uban] = UBAI_ADDR(info);
63830322Skarels 			else {
63930322Skarels 				printf(" [can't get uba map]");
64030322Skarels 				cbase[uban] = -1;
64130322Skarels 			}
64225433Skarels 		}
6432479Swnj 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
64416190Skarels 		((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
6452421Skre 		unit = dh * 16;
6462421Skre 		for (i = 0; i < 16; i++) {
6472421Skre 			tp = &dh11[unit];
6485406Swnj 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6492421Skre 				dhparam(unit);
6502479Swnj 				dmctl(unit, DML_ON, DMSET);
6515406Swnj 				tp->t_state &= ~TS_BUSY;
6522421Skre 				dhstart(tp);
6532421Skre 			}
6542421Skre 			unit++;
655300Sbill 		}
656300Sbill 	}
65716190Skarels 	dhsilos = 0;
658280Sbill }
6592395Swnj 
66016190Skarels int dhtransitions, dhslowtimers, dhfasttimers;		/*DEBUG*/
6612468Swnj /*
66216190Skarels  * At software clock interrupt time, check status.
66316190Skarels  * Empty all the dh silos that are in use, and decide whether
66416190Skarels  * to turn any silos off or on.
6652468Swnj  */
dhtimer()6662456Swnj dhtimer()
6672456Swnj {
66816190Skarels 	register int dh, s;
66916190Skarels 	static int timercalls;
6702456Swnj 
67116190Skarels 	if (dhsilos) {
67216190Skarels 		dhfasttimers++;		/*DEBUG*/
67316190Skarels 		timercalls++;
67416190Skarels 		s = spl5();
67516190Skarels 		for (dh = 0; dh < NDH; dh++)
67616190Skarels 			if (dhsilos & (1 << dh))
67716190Skarels 				dhrint(dh);
67816190Skarels 		splx(s);
67916190Skarels 	}
68016190Skarels 	if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
68116190Skarels 		dhslowtimers++;		/*DEBUG*/
68216190Skarels 		timercalls = 0;
68316190Skarels 		for (dh = 0; dh < NDH; dh++) {
68416190Skarels 		    ave(dhrate[dh], dhchars[dh], 8);
68516190Skarels 		    if ((dhchars[dh] > dhhighrate) &&
68616190Skarels 		      ((dhsilos & (1 << dh)) == 0)) {
68716190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
68816190Skarels 			    (dhchars[dh] > 500? 32 : 16);
68916190Skarels 			dhsilos |= (1 << dh);
69016190Skarels 			dhtransitions++;		/*DEBUG*/
69116190Skarels 		    } else if ((dhsilos & (1 << dh)) &&
69216190Skarels 		      (dhrate[dh] < dhlowrate)) {
69316190Skarels 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
69416190Skarels 			dhsilos &= ~(1 << dh);
69516190Skarels 		    }
69616190Skarels 		    dhchars[dh] = 0;
69716190Skarels 		}
69816190Skarels 	}
69916190Skarels 	timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
7002456Swnj }
7012456Swnj 
7022468Swnj /*
7032479Swnj  * Turn on the line associated with dh dev.
7042468Swnj  */
dmopen(dev,flag)70539061Smarc dmopen(dev, flag)
7062468Swnj 	dev_t dev;
7072468Swnj {
7082468Swnj 	register struct tty *tp;
7092468Swnj 	register struct dmdevice *addr;
7102974Swnj 	register struct uba_device *ui;
7112468Swnj 	register int unit;
7122468Swnj 	register int dm;
71340729Skarels 	int s, error = 0;
7142468Swnj 
7152468Swnj 	unit = minor(dev);
7162479Swnj 	dm = unit >> 4;
7172468Swnj 	tp = &dh11[unit];
7182566Swnj 	unit &= 0xf;
71916942Skarels 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
7205406Swnj 		tp->t_state |= TS_CARR_ON;
72140729Skarels 		return (0);
7222468Swnj 	}
7232468Swnj 	addr = (struct dmdevice *)ui->ui_addr;
7243792Swnj 	s = spl5();
72530341Skarels 	for (;;) {
72644393Smarc 		tp->t_state |= TS_WOPEN;
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;
73844393Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
73944393Smarc 		    ttopen, 0))
74040729Skarels 			break;
74130341Skarels 	}
7423792Swnj 	splx(s);
74340729Skarels 	return (error);
7442468Swnj }
7452468Swnj 
7462468Swnj /*
7472468Swnj  * Dump control bits into the DM registers.
7482468Swnj  */
dmctl(dev,bits,how)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  */
dmintr(dm)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