xref: /csrg-svn/sys/vax/uba/dhu.c (revision 45804)
123322Smckusick /*
229211Smckusick  * Copyright (c) 1985, 1986 Regents of the University of California.
323322Smckusick  * All rights reserved.  The Berkeley software License Agreement
423322Smckusick  * specifies the terms and conditions for redistribution.
523322Smckusick  *
6*45804Sbostic  *	@(#)dhu.c	7.13 (Berkeley) 12/16/90
723322Smckusick  */
820976Smckusick 
920976Smckusick /*
1020976Smckusick  * based on	dh.c 6.3	84/03/15
1120976Smckusick  * and on	dmf.c	6.2	84/02/16
1220976Smckusick  *
1320976Smckusick  * Dave Johnson, Brown University Computer Science
1420976Smckusick  *	ddj%brown@csnet-relay
1520976Smckusick  */
1620976Smckusick 
1720976Smckusick #include "dhu.h"
1820976Smckusick #if NDHU > 0
1920976Smckusick /*
2020976Smckusick  * DHU-11 driver
2120976Smckusick  */
22*45804Sbostic #include "../include/pte.h"
2320976Smckusick 
24*45804Sbostic #include "sys/param.h"
25*45804Sbostic #include "sys/conf.h"
26*45804Sbostic #include "sys/user.h"
27*45804Sbostic #include "sys/proc.h"
28*45804Sbostic #include "sys/ioctl.h"
29*45804Sbostic #include "sys/tty.h"
30*45804Sbostic #include "sys/ttydefaults.h"
31*45804Sbostic #include "sys/map.h"
32*45804Sbostic #include "sys/buf.h"
33*45804Sbostic #include "sys/vm.h"
34*45804Sbostic #include "sys/kernel.h"
35*45804Sbostic #include "sys/syslog.h"
3620976Smckusick 
3720976Smckusick #include "uba.h"
3820976Smckusick #include "ubareg.h"
3920976Smckusick #include "ubavar.h"
4020976Smckusick #include "dhureg.h"
4120976Smckusick 
42*45804Sbostic #include "sys/bkmac.h"
43*45804Sbostic #include "sys/clist.h"
44*45804Sbostic #include "sys/file.h"
45*45804Sbostic #include "sys/uio.h"
4620976Smckusick 
4720976Smckusick /*
4820976Smckusick  * Definition of the driver for the auto-configuration program.
4920976Smckusick  */
5020976Smckusick int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
5120976Smckusick struct	uba_device *dhuinfo[NDHU];
5225519Stef u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
5320976Smckusick struct	uba_driver dhudriver =
5420976Smckusick 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
5520976Smckusick 
5620976Smckusick #define	NDHULINE 	(NDHU*16)
5720976Smckusick 
5820976Smckusick #define	UNIT(x)	(minor(x))
5920976Smckusick 
6020976Smckusick #ifndef PORTSELECTOR
6137606Smarc #define SPEED	TTYDEF_SPEED
6237606Smarc #define LFLAG	TTYDEF_LFLAG
6320976Smckusick #else
6437606Smarc #define SPEED	B4800
6537606Smarc #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
6620976Smckusick #endif
6720976Smckusick 
6820976Smckusick /*
6920976Smckusick  * default receive silo timeout value -- valid values are 2..255
7020976Smckusick  * number of ms. to delay between first char received and receive interrupt
7120976Smckusick  *
7220976Smckusick  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
7320976Smckusick  */
7420976Smckusick #define	DHU_DEF_TIMO	20
7520976Smckusick 
7620976Smckusick /*
7720976Smckusick  * Other values for silo timeout register defined here but not used:
7820976Smckusick  * receive interrupt only on modem control or silo alarm (3/4 full)
7920976Smckusick  */
8020976Smckusick #define DHU_POLL_TIMO	0
8120976Smckusick /*
8220976Smckusick  * receive interrupt immediately on receive character
8320976Smckusick  */
8420976Smckusick #define DHU_NO_TIMO	1
8520976Smckusick 
8620976Smckusick /*
8720976Smckusick  * Local variables for the driver
8820976Smckusick  */
8920976Smckusick /*
9020976Smckusick  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
9120976Smckusick  *	EXTA => 19200 baud
9220976Smckusick  *	EXTB => 2000 baud
9320976Smckusick  */
9437606Smarc struct speedtab dhuspeedtab[] = {
9537606Smarc 	19200,	14,
9637606Smarc 	9600,	13,
9737606Smarc 	4800,	11,
9837606Smarc 	2400,	10,
9937606Smarc 	2000,	9,
10037606Smarc 	1800,	8,
10137606Smarc 	1200,	7,
10237606Smarc 	600,	6,
10337606Smarc 	300,	5,
10437606Smarc 	150,	4,
10537606Smarc 	134,	3,
10637606Smarc 	110,	2,
10737606Smarc 	75,	1,
10837606Smarc 	0,	0,
10939061Smarc 	EXTA,	14,
11039061Smarc 	EXTB,	9,
11137606Smarc 	-1,	-1,
11237606Smarc };
11320976Smckusick 
11420976Smckusick short	dhusoftCAR[NDHU];
11520976Smckusick 
11620976Smckusick struct	tty dhu_tty[NDHULINE];
11720976Smckusick int	ndhu = NDHULINE;
11820976Smckusick int	dhuact;				/* mask of active dhu's */
11920976Smckusick int	dhustart(), ttrstrt();
12020976Smckusick 
12120976Smckusick /*
12230322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
12330322Skarels  * The identity of the board which allocated resources is recorded,
12430322Skarels  * so the process may be repeated after UNIBUS resets.
12520976Smckusick  * The UBACVT macro converts a clist space address for unibus uban
12620976Smckusick  * into an i/o space address for the DMA routine.
12720976Smckusick  */
12830322Skarels int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
12930322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
13020976Smckusick #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
13120976Smckusick 
13220976Smckusick /*
13320976Smckusick  * Routine for configuration to force a dhu to interrupt.
13420976Smckusick  */
13520976Smckusick /*ARGSUSED*/
13620976Smckusick dhuprobe(reg)
13720976Smckusick 	caddr_t reg;
13820976Smckusick {
13920976Smckusick 	register int br, cvec;		/* these are ``value-result'' */
14020976Smckusick 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
14120976Smckusick 	int i;
14220976Smckusick 
14320976Smckusick #ifdef lint
14420976Smckusick 	br = 0; cvec = br; br = cvec;
14520976Smckusick 	if (ndhu == 0) ndhu = 1;
14620976Smckusick 	dhurint(0); dhuxint(0);
14720976Smckusick #endif
14820976Smckusick 	/*
14920976Smckusick 	 * The basic idea here is:
15020976Smckusick 	 *	do a self-test by setting the Master-Reset bit
15120976Smckusick 	 *	if this fails, then return
15220976Smckusick 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
15320976Smckusick 	 *	therefore ask for a  Received-Data-Available interrupt
15420976Smckusick 	 *	wait for it...
15520976Smckusick 	 *	reset the interrupt-enable bit and flush out the diag. codes
15620976Smckusick 	 */
15720976Smckusick 	dhuaddr->dhucsr = DHU_CS_MCLR;
15820976Smckusick 	for (i = 0; i < 1000; i++) {
15920976Smckusick 		DELAY(10000);
16020976Smckusick 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
16120976Smckusick 			break;
16220976Smckusick 	}
16320976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
16420976Smckusick 		return(0);
16520976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
16620976Smckusick 		return(0);
16720976Smckusick 	dhuaddr->dhucsr = DHU_CS_RIE;
16820976Smckusick 	DELAY(1000);
16920976Smckusick 	dhuaddr->dhucsr = 0;
17020976Smckusick 	while (dhuaddr->dhurbuf < 0)
17120976Smckusick 		/* void */;
17220976Smckusick 	return (sizeof(struct dhudevice));
17320976Smckusick }
17420976Smckusick 
17520976Smckusick /*
17620976Smckusick  * Routine called to attach a dhu.
17720976Smckusick  */
17820976Smckusick dhuattach(ui)
17920976Smckusick 	struct uba_device *ui;
18020976Smckusick {
18120976Smckusick 
18220976Smckusick 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
18326220Skarels 	cbase[ui->ui_ubanum] = -1;
18436610Sbostic 	dhu_uballoc[ui->ui_ubanum] = -1;
18520976Smckusick }
18620976Smckusick 
18720976Smckusick /*
18820976Smckusick  * Open a DHU11 line, mapping the clist onto the uba if this
18920976Smckusick  * is the first dhu on this uba.  Turn on this dhu if this is
19020976Smckusick  * the first use of it.
19120976Smckusick  */
19220976Smckusick /*ARGSUSED*/
19320976Smckusick dhuopen(dev, flag)
19420976Smckusick 	dev_t dev;
19520976Smckusick {
19620976Smckusick 	register struct tty *tp;
19720976Smckusick 	register int unit, dhu;
19820976Smckusick 	register struct dhudevice *addr;
19920976Smckusick 	register struct uba_device *ui;
20040729Skarels 	int s, error = 0;
20137606Smarc 	extern dhuparam();
20220976Smckusick 
20320976Smckusick 	unit = UNIT(dev);
20420976Smckusick 	dhu = unit >> 4;
20520976Smckusick 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
20620976Smckusick 		return (ENXIO);
20720976Smckusick 	tp = &dhu_tty[unit];
20820976Smckusick 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
20920976Smckusick 		return (EBUSY);
21020976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
21120976Smckusick 	tp->t_addr = (caddr_t)addr;
21220976Smckusick 	tp->t_oproc = dhustart;
21337606Smarc 	tp->t_param = dhuparam;
21420976Smckusick 	/*
21520976Smckusick 	 * While setting up state for this uba and this dhu,
21620976Smckusick 	 * block uba resets which can clear the state.
21720976Smckusick 	 */
21820976Smckusick 	s = spl5();
21926220Skarels 	if (cbase[ui->ui_ubanum] == -1) {
22030322Skarels 		dhu_uballoc[ui->ui_ubanum] = dhu;
22130322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22230322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22320976Smckusick 	}
22420976Smckusick 	if ((dhuact&(1<<dhu)) == 0) {
22520976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
22620976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
22720976Smckusick 		dhuact |= (1<<dhu);
22820976Smckusick 		/* anything else to configure whole board */
22920976Smckusick 	}
23020976Smckusick 	(void) splx(s);
23120976Smckusick 	/*
23220976Smckusick 	 * If this is first open, initialize tty state to default.
23320976Smckusick 	 */
23420976Smckusick 	if ((tp->t_state&TS_ISOPEN) == 0) {
23544393Smarc 		tp->t_state |= TS_WOPEN;
23620976Smckusick 		ttychars(tp);
23720976Smckusick #ifndef PORTSELECTOR
23837606Smarc 		if (tp->t_ospeed == 0) {
23937606Smarc #endif
24037606Smarc 			tp->t_ispeed = SPEED;
24137606Smarc 			tp->t_ospeed = SPEED;
24237606Smarc 			ttsetwater(tp);
24337606Smarc 			tp->t_iflag = TTYDEF_IFLAG;
24437606Smarc 			tp->t_oflag = TTYDEF_OFLAG;
24537606Smarc 			tp->t_lflag = LFLAG;
24637606Smarc 			tp->t_cflag = TTYDEF_CFLAG;
24737606Smarc #ifdef PORTSELECTOR
24837606Smarc 			tp->t_cflag |= HUPCL;
24937606Smarc #else
25020976Smckusick 		}
25137606Smarc #endif
25220976Smckusick 		tp->t_dev = dev;
25337606Smarc 		dhuparam(tp, &tp->t_termios);
25420976Smckusick 	}
25520976Smckusick 	/*
25620976Smckusick 	 * Wait for carrier, then process line discipline specific open.
25720976Smckusick 	 */
25837606Smarc 	s = spltty();
25920976Smckusick 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
26020976Smckusick 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
26120976Smckusick 		tp->t_state |= TS_CARR_ON;
26240729Skarels 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
26340729Skarels 	    (tp->t_state & TS_CARR_ON) == 0) {
26420976Smckusick 		tp->t_state |= TS_WOPEN;
26544393Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
26644393Smarc 		    ttopen, 0))
26740729Skarels 			break;
26820976Smckusick 	}
26920976Smckusick 	(void) splx(s);
27040729Skarels 	if (error)
27140729Skarels 		return (error);
27220976Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
27320976Smckusick }
27420976Smckusick 
27520976Smckusick /*
27620976Smckusick  * Close a DHU11 line, turning off the modem control.
27720976Smckusick  */
27820976Smckusick /*ARGSUSED*/
27920976Smckusick dhuclose(dev, flag)
28020976Smckusick 	dev_t dev;
28120976Smckusick 	int flag;
28220976Smckusick {
28320976Smckusick 	register struct tty *tp;
28420976Smckusick 	register unit;
28520976Smckusick 
28620976Smckusick 	unit = UNIT(dev);
28720976Smckusick 	tp = &dhu_tty[unit];
28820976Smckusick 	(*linesw[tp->t_line].l_close)(tp);
28920976Smckusick 	(void) dhumctl(unit, DHU_BRK, DMBIC);
29037606Smarc 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
29140729Skarels 	    (tp->t_state&TS_ISOPEN) == 0) {
29220976Smckusick #ifdef PORTSELECTOR
29320976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29420976Smckusick 		/* Hold DTR low for 0.5 seconds */
29540729Skarels 		(void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2);
29620976Smckusick #else
29720976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29820976Smckusick #endif PORTSELECTOR
29940729Skarels 	}
30040729Skarels 	return (ttyclose(tp));
30120976Smckusick }
30220976Smckusick 
30339061Smarc dhuread(dev, uio, flag)
30420976Smckusick 	dev_t dev;
30520976Smckusick 	struct uio *uio;
30620976Smckusick {
30720976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
30820976Smckusick 
30939061Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
31020976Smckusick }
31120976Smckusick 
31239061Smarc dhuwrite(dev, uio, flag)
31320976Smckusick 	dev_t dev;
31420976Smckusick 	struct uio *uio;
31520976Smckusick {
31620976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
31720976Smckusick 
31839061Smarc 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
31920976Smckusick }
32020976Smckusick 
32120976Smckusick /*
32220976Smckusick  * DHU11 receiver interrupt.
32320976Smckusick  */
32420976Smckusick dhurint(dhu)
32520976Smckusick 	int dhu;
32620976Smckusick {
32720976Smckusick 	register struct tty *tp;
32837606Smarc 	register creg, c;
32920976Smckusick 	register struct dhudevice *addr;
33020976Smckusick 	register struct tty *tp0;
33120976Smckusick 	register struct uba_device *ui;
33220976Smckusick 	register line;
33320976Smckusick 	int overrun = 0;
33420976Smckusick 
33535401Stef #ifdef QBA
33637606Smarc 	(void) spltty();
33727256Skridle #endif
33820976Smckusick 	ui = dhuinfo[dhu];
33920976Smckusick 	if (ui == 0 || ui->ui_alive == 0)
34020976Smckusick 		return;
34120976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
34220976Smckusick 	tp0 = &dhu_tty[dhu<<4];
34320976Smckusick 	/*
34420976Smckusick 	 * Loop fetching characters from the silo for this
34520976Smckusick 	 * dhu until there are no more in the silo.
34620976Smckusick 	 */
34737606Smarc 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
34837606Smarc 		line = DHU_RX_LINE(creg);
34920976Smckusick 		tp = tp0 + line;
35037606Smarc 		c = creg & 0xff;
35137606Smarc 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
35220976Smckusick 			/*
35320976Smckusick 			 * modem changed or diag info
35420976Smckusick 			 */
35537606Smarc 			if (creg & DHU_RB_DIAG) {
35620976Smckusick 				/* decode diagnostic messages */
35720976Smckusick 				continue;
35820976Smckusick 			}
35937606Smarc 			if (creg & DHU_ST_DCD)
36025395Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
36125395Skarels 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
36225395Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36325395Skarels 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
36420976Smckusick 			continue;
36520976Smckusick 		}
36620976Smckusick 		if ((tp->t_state&TS_ISOPEN) == 0) {
36720976Smckusick 			wakeup((caddr_t)&tp->t_rawq);
36820976Smckusick #ifdef PORTSELECTOR
36920976Smckusick 			if ((tp->t_state&TS_WOPEN) == 0)
37020976Smckusick #endif
37125395Skarels 				continue;
37220976Smckusick 		}
37339061Smarc 		if (creg & DHU_RB_PE)
37439061Smarc 			c |= TTY_PE;
37539061Smarc 		if (creg & DHU_RB_DO && overrun == 0) {
37639061Smarc 			log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
37739061Smarc 			overrun = 1;
37820976Smckusick 		}
37939061Smarc 		if (creg & DHU_RB_FE)
38039061Smarc 			c |= TTY_FE;
38137606Smarc 
38239061Smarc 		(*linesw[tp->t_line].l_rint)(c, tp);
38320976Smckusick 	}
38420976Smckusick }
38520976Smckusick 
38620976Smckusick /*
38720976Smckusick  * Ioctl for DHU11.
38820976Smckusick  */
38920976Smckusick /*ARGSUSED*/
39020976Smckusick dhuioctl(dev, cmd, data, flag)
39120976Smckusick 	caddr_t data;
39220976Smckusick {
39320976Smckusick 	register struct tty *tp;
39420976Smckusick 	register int unit = UNIT(dev);
39520976Smckusick 	int error;
39620976Smckusick 
39720976Smckusick 	tp = &dhu_tty[unit];
39820976Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
39920976Smckusick 	if (error >= 0)
40020976Smckusick 		return (error);
40120976Smckusick 	error = ttioctl(tp, cmd, data, flag);
40237606Smarc 	if (error >= 0)
40320976Smckusick 		return (error);
40420976Smckusick 
40520976Smckusick 	switch (cmd) {
40620976Smckusick 	case TIOCSBRK:
40720976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIS);
40820976Smckusick 		break;
40920976Smckusick 
41020976Smckusick 	case TIOCCBRK:
41120976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIC);
41220976Smckusick 		break;
41320976Smckusick 
41420976Smckusick 	case TIOCSDTR:
41520976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
41620976Smckusick 		break;
41720976Smckusick 
41820976Smckusick 	case TIOCCDTR:
41920976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
42020976Smckusick 		break;
42120976Smckusick 
42220976Smckusick 	case TIOCMSET:
42320976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
42420976Smckusick 		break;
42520976Smckusick 
42620976Smckusick 	case TIOCMBIS:
42720976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
42820976Smckusick 		break;
42920976Smckusick 
43020976Smckusick 	case TIOCMBIC:
43120976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
43220976Smckusick 		break;
43320976Smckusick 
43420976Smckusick 	case TIOCMGET:
43520976Smckusick 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
43620976Smckusick 		break;
43720976Smckusick 	default:
43820976Smckusick 		return (ENOTTY);
43920976Smckusick 	}
44020976Smckusick 	return (0);
44120976Smckusick }
44220976Smckusick 
44320976Smckusick dmtodhu(bits)
44420976Smckusick 	register int bits;
44520976Smckusick {
44620976Smckusick 	register int b = 0;
44720976Smckusick 
44820976Smckusick 	if (bits & DML_RTS) b |= DHU_RTS;
44920976Smckusick 	if (bits & DML_DTR) b |= DHU_DTR;
45020976Smckusick 	if (bits & DML_LE) b |= DHU_LE;
45120976Smckusick 	return(b);
45220976Smckusick }
45320976Smckusick 
45420976Smckusick dhutodm(bits)
45520976Smckusick 	register int bits;
45620976Smckusick {
45720976Smckusick 	register int b = 0;
45820976Smckusick 
45920976Smckusick 	if (bits & DHU_DSR) b |= DML_DSR;
46020976Smckusick 	if (bits & DHU_RNG) b |= DML_RNG;
46120976Smckusick 	if (bits & DHU_CAR) b |= DML_CAR;
46220976Smckusick 	if (bits & DHU_CTS) b |= DML_CTS;
46320976Smckusick 	if (bits & DHU_RTS) b |= DML_RTS;
46420976Smckusick 	if (bits & DHU_DTR) b |= DML_DTR;
46520976Smckusick 	if (bits & DHU_LE) b |= DML_LE;
46620976Smckusick 	return(b);
46720976Smckusick }
46820976Smckusick 
46920976Smckusick 
47020976Smckusick /*
47120976Smckusick  * Set parameters from open or stty into the DHU hardware
47237606Smarc  * registers.  Impossible values for speed or character
47337606Smarc  * size are ignored and not copied back into tp.
47420976Smckusick  */
47537606Smarc dhuparam(tp, want)
47637606Smarc 	register struct tty *tp;
47737606Smarc 	register struct termios *want;
47820976Smckusick {
47937606Smarc 	register int unit = UNIT(tp->t_dev);
48037606Smarc 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
48120976Smckusick 	register int lpar;
48237606Smarc 	register long cflag;
48337606Smarc 	register int incode, outcode;
48420976Smckusick 	int s;
48537606Smarc 
48620976Smckusick 	/*
48720976Smckusick 	 * Block interrupts so parameters will be set
48820976Smckusick 	 * before the line interrupts.
48920976Smckusick 	 */
49037606Smarc 	s = spltty();
49137606Smarc 
49237606Smarc 	if (want->c_ospeed == 0) {
49337606Smarc 		tp->t_ospeed = 0;
49437606Smarc 		tp->t_cflag |= HUPCL;
49520976Smckusick 		(void)dhumctl(unit, DHU_OFF, DMSET);
49620976Smckusick 		splx(s);
49720976Smckusick 		return;
49820976Smckusick 	}
49937606Smarc 
50037606Smarc 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
50137606Smarc 		tp->t_ospeed = want->c_ospeed;
50237606Smarc 	else
50337606Smarc 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
50437606Smarc 
50537606Smarc 	if (want->c_ispeed == 0) {
50637606Smarc 		tp->t_ispeed = 0;
50737606Smarc 		incode = outcode;
50837606Smarc 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
50937606Smarc 		tp->t_ispeed = want->c_ispeed;
51037606Smarc 	else
51137606Smarc 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
51237606Smarc 
51337606Smarc 	lpar = ((char)outcode<<12) | ((char)incode<<8);
51437606Smarc 
51537606Smarc 	switch (want->c_cflag&CSIZE) {
51637606Smarc 	case CS6: case CS7: case CS8:
51737606Smarc 		tp->t_cflag =  want->c_cflag;
51837606Smarc 		break;
51937606Smarc 	default:
52037606Smarc 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
52137606Smarc 	}
52237606Smarc 	cflag = tp->t_cflag;
52337606Smarc 
52437606Smarc 	switch(cflag&CSIZE) {
52537606Smarc 	case CS6:
52637606Smarc 		lpar |= DHU_LP_BITS6;
52737606Smarc 		break;
52837606Smarc 	case CS7:
52937606Smarc 		lpar |= DHU_LP_BITS7;
53037606Smarc 		break;
53137606Smarc 	case CS8:
53220976Smckusick 		lpar |= DHU_LP_BITS8;
53337606Smarc 		break;
53437606Smarc 	}
53537606Smarc 	if (cflag&PARENB) {
53637606Smarc 		lpar |= DHU_LP_PENABLE;
53737606Smarc 		if ((cflag&PARODD) == 0)
53837606Smarc 			lpar |= DHU_LP_EPAR;
53937606Smarc 	}
54037606Smarc 	if (cflag&CSTOPB)
54137606Smarc 		lpar |= DHU_LP_TWOSB;
54237606Smarc 
54339061Smarc 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
54420976Smckusick 	addr->dhulpr = lpar;
54520976Smckusick 	splx(s);
54620976Smckusick }
54720976Smckusick 
54820976Smckusick /*
54920976Smckusick  * DHU11 transmitter interrupt.
55020976Smckusick  * Restart each line which used to be active but has
55120976Smckusick  * terminated transmission since the last interrupt.
55220976Smckusick  */
55320976Smckusick dhuxint(dhu)
55420976Smckusick 	int dhu;
55520976Smckusick {
55620976Smckusick 	register struct tty *tp;
55720976Smckusick 	register struct dhudevice *addr;
55820976Smckusick 	register struct tty *tp0;
55920976Smckusick 	register struct uba_device *ui;
56020976Smckusick 	register int line, t;
56120976Smckusick 	u_short cntr;
56220976Smckusick 
56335401Stef #ifdef QBA
56427256Skridle 	(void) spl5();
56527256Skridle #endif
56620976Smckusick 	ui = dhuinfo[dhu];
56720976Smckusick 	tp0 = &dhu_tty[dhu<<4];
56820976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
56920976Smckusick 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
57020976Smckusick 		line = DHU_TX_LINE(t);
57120976Smckusick 		tp = tp0 + line;
57220976Smckusick 		tp->t_state &= ~TS_BUSY;
57320976Smckusick 		if (t & DHU_CSH_NXM) {
57420976Smckusick 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
57520976Smckusick 			/* SHOULD RESTART OR SOMETHING... */
57620976Smckusick 		}
57720976Smckusick 		if (tp->t_state&TS_FLUSH)
57820976Smckusick 			tp->t_state &= ~TS_FLUSH;
57920976Smckusick 		else {
58020976Smckusick 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
58120976Smckusick 			/*
58220976Smckusick 			 * Do arithmetic in a short to make up
58320976Smckusick 			 * for lost 16&17 bits.
58420976Smckusick 			 */
58520976Smckusick 			cntr = addr->dhubar1 -
58620976Smckusick 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
58720976Smckusick 			ndflush(&tp->t_outq, (int)cntr);
58820976Smckusick 		}
58920976Smckusick 		if (tp->t_line)
59020976Smckusick 			(*linesw[tp->t_line].l_start)(tp);
59120976Smckusick 		else
59220976Smckusick 			dhustart(tp);
59320976Smckusick 	}
59420976Smckusick }
59520976Smckusick 
59620976Smckusick /*
59720976Smckusick  * Start (restart) transmission on the given DHU11 line.
59820976Smckusick  */
59920976Smckusick dhustart(tp)
60020976Smckusick 	register struct tty *tp;
60120976Smckusick {
60220976Smckusick 	register struct dhudevice *addr;
60320976Smckusick 	register int car, dhu, unit, nch;
60420976Smckusick 	int s;
60520976Smckusick 
60620976Smckusick 	unit = minor(tp->t_dev);
60720976Smckusick 	dhu = unit >> 4;
60820976Smckusick 	unit &= 0xf;
60920976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
61020976Smckusick 
61120976Smckusick 	/*
61220976Smckusick 	 * Must hold interrupts in following code to prevent
61320976Smckusick 	 * state of the tp from changing.
61420976Smckusick 	 */
61520976Smckusick 	s = spl5();
61620976Smckusick 	/*
61720976Smckusick 	 * If it's currently active, or delaying, no need to do anything.
61820976Smckusick 	 */
61920976Smckusick 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
62020976Smckusick 		goto out;
62120976Smckusick 	/*
62220976Smckusick 	 * If there are sleepers, and output has drained below low
62320976Smckusick 	 * water mark, wake up the sleepers..
62420976Smckusick 	 */
62537606Smarc 	if (tp->t_outq.c_cc <= tp->t_lowat) {
62620976Smckusick 		if (tp->t_state&TS_ASLEEP) {
62720976Smckusick 			tp->t_state &= ~TS_ASLEEP;
62820976Smckusick 			wakeup((caddr_t)&tp->t_outq);
62920976Smckusick 		}
63020976Smckusick 		if (tp->t_wsel) {
63120976Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
63220976Smckusick 			tp->t_wsel = 0;
63320976Smckusick 			tp->t_state &= ~TS_WCOLL;
63420976Smckusick 		}
63520976Smckusick 	}
63620976Smckusick 	/*
63720976Smckusick 	 * Now restart transmission unless the output queue is
63820976Smckusick 	 * empty.
63920976Smckusick 	 */
64020976Smckusick 	if (tp->t_outq.c_cc == 0)
64120976Smckusick 		goto out;
64239061Smarc 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
64320976Smckusick 		nch = ndqb(&tp->t_outq, 0);
64420976Smckusick 	else {
64520976Smckusick 		nch = ndqb(&tp->t_outq, 0200);
64620976Smckusick 		/*
64720976Smckusick 		 * If first thing on queue is a delay process it.
64820976Smckusick 		 */
64920976Smckusick 		if (nch == 0) {
65020976Smckusick 			nch = getc(&tp->t_outq);
65120976Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
65220976Smckusick 			tp->t_state |= TS_TIMEOUT;
65320976Smckusick 			goto out;
65420976Smckusick 		}
65520976Smckusick 	}
65620976Smckusick 	/*
65720976Smckusick 	 * If characters to transmit, restart transmission.
65820976Smckusick 	 */
65920976Smckusick 	if (nch) {
66020976Smckusick 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
66120976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
66220976Smckusick 		addr->dhulcr &= ~DHU_LC_TXABORT;
66320976Smckusick 		addr->dhubcr = nch;
66420976Smckusick 		addr->dhubar1 = car;
66520976Smckusick 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
66620976Smckusick 					DHU_BA2_DMAGO;
66720976Smckusick 		tp->t_state |= TS_BUSY;
66820976Smckusick 	}
66920976Smckusick out:
67020976Smckusick 	splx(s);
67120976Smckusick }
67220976Smckusick 
67320976Smckusick /*
67420976Smckusick  * Stop output on a line, e.g. for ^S/^Q or output flush.
67520976Smckusick  */
67620976Smckusick /*ARGSUSED*/
67720976Smckusick dhustop(tp, flag)
67820976Smckusick 	register struct tty *tp;
67920976Smckusick {
68020976Smckusick 	register struct dhudevice *addr;
68120976Smckusick 	register int unit, s;
68220976Smckusick 
68320976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
68420976Smckusick 	/*
68520976Smckusick 	 * Block input/output interrupts while messing with state.
68620976Smckusick 	 */
68720976Smckusick 	s = spl5();
68820976Smckusick 	if (tp->t_state & TS_BUSY) {
68920976Smckusick 		/*
69020976Smckusick 		 * Device is transmitting; stop output
69120976Smckusick 		 * by selecting the line and setting the
69220976Smckusick 		 * abort xmit bit.  We will get an xmit interrupt,
69320976Smckusick 		 * where we will figure out where to continue the
69420976Smckusick 		 * next time the transmitter is enabled.  If
69520976Smckusick 		 * TS_FLUSH is set, the outq will be flushed.
69620976Smckusick 		 * In either case, dhustart will clear the TXABORT bit.
69720976Smckusick 		 */
69820976Smckusick 		unit = minor(tp->t_dev);
69920976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
70020976Smckusick 		addr->dhulcr |= DHU_LC_TXABORT;
70120976Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
70220976Smckusick 			tp->t_state |= TS_FLUSH;
70320976Smckusick 	}
70420976Smckusick 	(void) splx(s);
70520976Smckusick }
70620976Smckusick 
70720976Smckusick /*
70820976Smckusick  * DHU11 modem control
70920976Smckusick  */
71020976Smckusick dhumctl(dev, bits, how)
71120976Smckusick 	dev_t dev;
71220976Smckusick 	int bits, how;
71320976Smckusick {
71420976Smckusick 	register struct dhudevice *dhuaddr;
71526291Skarels 	register int unit, mbits;
71620976Smckusick 	int s;
71720976Smckusick 
71820976Smckusick 	unit = UNIT(dev);
71920976Smckusick 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
72020976Smckusick 	unit &= 0xf;
72120976Smckusick 	s = spl5();
72220976Smckusick 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
72320976Smckusick 	/*
72420976Smckusick 	 * combine byte from stat register (read only, bits 16..23)
72520976Smckusick 	 * with lcr register (read write, bits 0..15).
72620976Smckusick 	 */
72720976Smckusick 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
72820976Smckusick 	switch (how) {
72920976Smckusick 	case DMSET:
73020976Smckusick 		mbits = (mbits & 0xff0000) | bits;
73120976Smckusick 		break;
73220976Smckusick 
73320976Smckusick 	case DMBIS:
73420976Smckusick 		mbits |= bits;
73520976Smckusick 		break;
73620976Smckusick 
73720976Smckusick 	case DMBIC:
73820976Smckusick 		mbits &= ~bits;
73920976Smckusick 		break;
74020976Smckusick 
74120976Smckusick 	case DMGET:
74220976Smckusick 		(void) splx(s);
74320976Smckusick 		return(mbits);
74420976Smckusick 	}
74520976Smckusick 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
74620976Smckusick 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
74720976Smckusick 	(void) splx(s);
74820976Smckusick 	return(mbits);
74920976Smckusick }
75020976Smckusick 
75120976Smckusick /*
75220976Smckusick  * Reset state of driver if UBA reset was necessary.
75320976Smckusick  * Reset the line and modem control registers.
75420976Smckusick  * restart transmitters.
75520976Smckusick  */
75620976Smckusick dhureset(uban)
75720976Smckusick 	int uban;
75820976Smckusick {
75920976Smckusick 	register int dhu, unit;
76020976Smckusick 	register struct tty *tp;
76120976Smckusick 	register struct uba_device *ui;
76220976Smckusick 	register struct dhudevice *addr;
76320976Smckusick 	int i;
76420976Smckusick 
76520976Smckusick 	for (dhu = 0; dhu < NDHU; dhu++) {
76620976Smckusick 		ui = dhuinfo[dhu];
76720976Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
76820976Smckusick 			continue;
76920976Smckusick 		printf(" dhu%d", dhu);
77030322Skarels 		if (dhu_uballoc[uban] == dhu) {
77130322Skarels 			int info;
77230322Skarels 
77330322Skarels 			info = uballoc(uban, (caddr_t)cfree,
77430322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
77530322Skarels 			if (info)
77630322Skarels 				cbase[uban] = UBAI_ADDR(info);
77730322Skarels 			else {
77830322Skarels 				printf(" [can't get uba map]");
77930322Skarels 				cbase[uban] = -1;
78030322Skarels 			}
78125434Skarels 		}
78220976Smckusick 		addr = (struct dhudevice *)ui->ui_addr;
78320976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
78420976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
78520976Smckusick 		unit = dhu * 16;
78620976Smckusick 		for (i = 0; i < 16; i++) {
78720976Smckusick 			tp = &dhu_tty[unit];
78820976Smckusick 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
78937606Smarc 				dhuparam(tp, &tp->t_termios);
79020976Smckusick 				(void)dhumctl(unit, DHU_ON, DMSET);
79120976Smckusick 				tp->t_state &= ~TS_BUSY;
79220976Smckusick 				dhustart(tp);
79320976Smckusick 			}
79420976Smckusick 			unit++;
79520976Smckusick 		}
79620976Smckusick 	}
79720976Smckusick }
79820976Smckusick #endif
799