xref: /csrg-svn/sys/vax/uba/dhu.c (revision 39061)
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*39061Smarc  *	@(#)dhu.c	7.7 (Berkeley) 09/06/89
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  */
2237514Smckusick #include "machine/pte.h"
2320976Smckusick 
2420976Smckusick #include "bk.h"
2520976Smckusick #include "param.h"
2620976Smckusick #include "conf.h"
2720976Smckusick #include "dir.h"
2820976Smckusick #include "user.h"
2920976Smckusick #include "proc.h"
3020976Smckusick #include "ioctl.h"
3120976Smckusick #include "tty.h"
3237606Smarc #include "ttydefaults.h"
3320976Smckusick #include "map.h"
3420976Smckusick #include "buf.h"
3520976Smckusick #include "vm.h"
3620976Smckusick #include "kernel.h"
3720976Smckusick #include "syslog.h"
3820976Smckusick 
3920976Smckusick #include "uba.h"
4020976Smckusick #include "ubareg.h"
4120976Smckusick #include "ubavar.h"
4220976Smckusick #include "dhureg.h"
4320976Smckusick 
4420976Smckusick #include "bkmac.h"
4520976Smckusick #include "clist.h"
4620976Smckusick #include "file.h"
4720976Smckusick #include "uio.h"
4820976Smckusick 
4920976Smckusick /*
5020976Smckusick  * Definition of the driver for the auto-configuration program.
5120976Smckusick  */
5220976Smckusick int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
5320976Smckusick struct	uba_device *dhuinfo[NDHU];
5425519Stef u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
5520976Smckusick struct	uba_driver dhudriver =
5620976Smckusick 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
5720976Smckusick 
5820976Smckusick #define	NDHULINE 	(NDHU*16)
5920976Smckusick 
6020976Smckusick #define	UNIT(x)	(minor(x))
6120976Smckusick 
6220976Smckusick #ifndef PORTSELECTOR
6337606Smarc #define SPEED	TTYDEF_SPEED
6437606Smarc #define LFLAG	TTYDEF_LFLAG
6520976Smckusick #else
6637606Smarc #define SPEED	B4800
6737606Smarc #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
6820976Smckusick #endif
6920976Smckusick 
7020976Smckusick /*
7120976Smckusick  * default receive silo timeout value -- valid values are 2..255
7220976Smckusick  * number of ms. to delay between first char received and receive interrupt
7320976Smckusick  *
7420976Smckusick  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
7520976Smckusick  */
7620976Smckusick #define	DHU_DEF_TIMO	20
7720976Smckusick 
7820976Smckusick /*
7920976Smckusick  * Other values for silo timeout register defined here but not used:
8020976Smckusick  * receive interrupt only on modem control or silo alarm (3/4 full)
8120976Smckusick  */
8220976Smckusick #define DHU_POLL_TIMO	0
8320976Smckusick /*
8420976Smckusick  * receive interrupt immediately on receive character
8520976Smckusick  */
8620976Smckusick #define DHU_NO_TIMO	1
8720976Smckusick 
8820976Smckusick /*
8920976Smckusick  * Local variables for the driver
9020976Smckusick  */
9120976Smckusick /*
9220976Smckusick  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
9320976Smckusick  *	EXTA => 19200 baud
9420976Smckusick  *	EXTB => 2000 baud
9520976Smckusick  */
9637606Smarc struct speedtab dhuspeedtab[] = {
9737606Smarc 	19200,	14,
9837606Smarc 	9600,	13,
9937606Smarc 	4800,	11,
10037606Smarc 	2400,	10,
10137606Smarc 	2000,	9,
10237606Smarc 	1800,	8,
10337606Smarc 	1200,	7,
10437606Smarc 	600,	6,
10537606Smarc 	300,	5,
10637606Smarc 	150,	4,
10737606Smarc 	134,	3,
10837606Smarc 	110,	2,
10937606Smarc 	75,	1,
11037606Smarc 	0,	0,
111*39061Smarc 	EXTA,	14,
112*39061Smarc 	EXTB,	9,
11337606Smarc 	-1,	-1,
11437606Smarc };
11520976Smckusick 
11620976Smckusick short	dhusoftCAR[NDHU];
11720976Smckusick 
11820976Smckusick struct	tty dhu_tty[NDHULINE];
11920976Smckusick int	ndhu = NDHULINE;
12020976Smckusick int	dhuact;				/* mask of active dhu's */
12120976Smckusick int	dhustart(), ttrstrt();
12220976Smckusick 
12320976Smckusick /*
12430322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
12530322Skarels  * The identity of the board which allocated resources is recorded,
12630322Skarels  * so the process may be repeated after UNIBUS resets.
12720976Smckusick  * The UBACVT macro converts a clist space address for unibus uban
12820976Smckusick  * into an i/o space address for the DMA routine.
12920976Smckusick  */
13030322Skarels int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
13130322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
13220976Smckusick #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
13320976Smckusick 
13420976Smckusick /*
13520976Smckusick  * Routine for configuration to force a dhu to interrupt.
13620976Smckusick  */
13720976Smckusick /*ARGSUSED*/
13820976Smckusick dhuprobe(reg)
13920976Smckusick 	caddr_t reg;
14020976Smckusick {
14120976Smckusick 	register int br, cvec;		/* these are ``value-result'' */
14220976Smckusick 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
14320976Smckusick 	int i;
14420976Smckusick 
14520976Smckusick #ifdef lint
14620976Smckusick 	br = 0; cvec = br; br = cvec;
14720976Smckusick 	if (ndhu == 0) ndhu = 1;
14820976Smckusick 	dhurint(0); dhuxint(0);
14920976Smckusick #endif
15020976Smckusick 	/*
15120976Smckusick 	 * The basic idea here is:
15220976Smckusick 	 *	do a self-test by setting the Master-Reset bit
15320976Smckusick 	 *	if this fails, then return
15420976Smckusick 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
15520976Smckusick 	 *	therefore ask for a  Received-Data-Available interrupt
15620976Smckusick 	 *	wait for it...
15720976Smckusick 	 *	reset the interrupt-enable bit and flush out the diag. codes
15820976Smckusick 	 */
15920976Smckusick 	dhuaddr->dhucsr = DHU_CS_MCLR;
16020976Smckusick 	for (i = 0; i < 1000; i++) {
16120976Smckusick 		DELAY(10000);
16220976Smckusick 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
16320976Smckusick 			break;
16420976Smckusick 	}
16520976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
16620976Smckusick 		return(0);
16720976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
16820976Smckusick 		return(0);
16920976Smckusick 	dhuaddr->dhucsr = DHU_CS_RIE;
17020976Smckusick 	DELAY(1000);
17120976Smckusick 	dhuaddr->dhucsr = 0;
17220976Smckusick 	while (dhuaddr->dhurbuf < 0)
17320976Smckusick 		/* void */;
17420976Smckusick 	return (sizeof(struct dhudevice));
17520976Smckusick }
17620976Smckusick 
17720976Smckusick /*
17820976Smckusick  * Routine called to attach a dhu.
17920976Smckusick  */
18020976Smckusick dhuattach(ui)
18120976Smckusick 	struct uba_device *ui;
18220976Smckusick {
18320976Smckusick 
18420976Smckusick 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
18526220Skarels 	cbase[ui->ui_ubanum] = -1;
18636610Sbostic 	dhu_uballoc[ui->ui_ubanum] = -1;
18720976Smckusick }
18820976Smckusick 
18920976Smckusick /*
19020976Smckusick  * Open a DHU11 line, mapping the clist onto the uba if this
19120976Smckusick  * is the first dhu on this uba.  Turn on this dhu if this is
19220976Smckusick  * the first use of it.
19320976Smckusick  */
19420976Smckusick /*ARGSUSED*/
19520976Smckusick dhuopen(dev, flag)
19620976Smckusick 	dev_t dev;
19720976Smckusick {
19820976Smckusick 	register struct tty *tp;
19920976Smckusick 	register int unit, dhu;
20020976Smckusick 	register struct dhudevice *addr;
20120976Smckusick 	register struct uba_device *ui;
20220976Smckusick 	int s;
20337606Smarc 	extern dhuparam();
20420976Smckusick 
20520976Smckusick 	unit = UNIT(dev);
20620976Smckusick 	dhu = unit >> 4;
20720976Smckusick 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
20820976Smckusick 		return (ENXIO);
20920976Smckusick 	tp = &dhu_tty[unit];
21020976Smckusick 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
21120976Smckusick 		return (EBUSY);
21220976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
21320976Smckusick 	tp->t_addr = (caddr_t)addr;
21420976Smckusick 	tp->t_oproc = dhustart;
21537606Smarc 	tp->t_param = dhuparam;
21620976Smckusick 	/*
21720976Smckusick 	 * While setting up state for this uba and this dhu,
21820976Smckusick 	 * block uba resets which can clear the state.
21920976Smckusick 	 */
22020976Smckusick 	s = spl5();
22126220Skarels 	if (cbase[ui->ui_ubanum] == -1) {
22230322Skarels 		dhu_uballoc[ui->ui_ubanum] = dhu;
22330322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22430322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22520976Smckusick 	}
22620976Smckusick 	if ((dhuact&(1<<dhu)) == 0) {
22720976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
22820976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
22920976Smckusick 		dhuact |= (1<<dhu);
23020976Smckusick 		/* anything else to configure whole board */
23120976Smckusick 	}
23220976Smckusick 	(void) splx(s);
23320976Smckusick 	/*
23420976Smckusick 	 * If this is first open, initialize tty state to default.
23520976Smckusick 	 */
23620976Smckusick 	if ((tp->t_state&TS_ISOPEN) == 0) {
23720976Smckusick 		ttychars(tp);
23820976Smckusick #ifndef PORTSELECTOR
23937606Smarc 		if (tp->t_ospeed == 0) {
24037606Smarc #endif
24137606Smarc 			tp->t_ispeed = SPEED;
24237606Smarc 			tp->t_ospeed = SPEED;
24337606Smarc 			ttsetwater(tp);
24437606Smarc 			tp->t_iflag = TTYDEF_IFLAG;
24537606Smarc 			tp->t_oflag = TTYDEF_OFLAG;
24637606Smarc 			tp->t_lflag = LFLAG;
24737606Smarc 			tp->t_cflag = TTYDEF_CFLAG;
24837606Smarc #ifdef PORTSELECTOR
24937606Smarc 			tp->t_cflag |= HUPCL;
25037606Smarc #else
25120976Smckusick 		}
25237606Smarc #endif
25320976Smckusick 		tp->t_dev = dev;
25437606Smarc 		dhuparam(tp, &tp->t_termios);
25520976Smckusick 	}
25620976Smckusick 	/*
25720976Smckusick 	 * Wait for carrier, then process line discipline specific open.
25820976Smckusick 	 */
25937606Smarc 	s = spltty();
26020976Smckusick 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
26120976Smckusick 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
26220976Smckusick 		tp->t_state |= TS_CARR_ON;
263*39061Smarc 	while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
264*39061Smarc 	       (tp->t_state & TS_CARR_ON) == 0) {
26520976Smckusick 		tp->t_state |= TS_WOPEN;
26620976Smckusick 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
26720976Smckusick 	}
26820976Smckusick 	(void) splx(s);
26920976Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
27020976Smckusick }
27120976Smckusick 
27220976Smckusick /*
27320976Smckusick  * Close a DHU11 line, turning off the modem control.
27420976Smckusick  */
27520976Smckusick /*ARGSUSED*/
27620976Smckusick dhuclose(dev, flag)
27720976Smckusick 	dev_t dev;
27820976Smckusick 	int flag;
27920976Smckusick {
28020976Smckusick 	register struct tty *tp;
28120976Smckusick 	register unit;
28220976Smckusick 
28320976Smckusick 	unit = UNIT(dev);
28420976Smckusick 	tp = &dhu_tty[unit];
28520976Smckusick 	(*linesw[tp->t_line].l_close)(tp);
28620976Smckusick 	(void) dhumctl(unit, DHU_BRK, DMBIC);
28737606Smarc 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
28837606Smarc 	    (tp->t_state&TS_ISOPEN)==0)
28920976Smckusick #ifdef PORTSELECTOR
29020976Smckusick 	{
29120976Smckusick 		extern int wakeup();
29220976Smckusick 
29320976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29420976Smckusick 		/* Hold DTR low for 0.5 seconds */
29520976Smckusick 		timeout(wakeup, (caddr_t) &tp->t_dev, hz/2);
29620976Smckusick 		sleep((caddr_t) &tp->t_dev, PZERO);
29720976Smckusick 	}
29820976Smckusick #else
29920976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
30020976Smckusick #endif PORTSELECTOR
30120976Smckusick 	ttyclose(tp);
30220976Smckusick }
30320976Smckusick 
304*39061Smarc dhuread(dev, uio, flag)
30520976Smckusick 	dev_t dev;
30620976Smckusick 	struct uio *uio;
30720976Smckusick {
30820976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
30920976Smckusick 
310*39061Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
31120976Smckusick }
31220976Smckusick 
313*39061Smarc dhuwrite(dev, uio, flag)
31420976Smckusick 	dev_t dev;
31520976Smckusick 	struct uio *uio;
31620976Smckusick {
31720976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
31820976Smckusick 
319*39061Smarc 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
32020976Smckusick }
32120976Smckusick 
32220976Smckusick /*
32320976Smckusick  * DHU11 receiver interrupt.
32420976Smckusick  */
32520976Smckusick dhurint(dhu)
32620976Smckusick 	int dhu;
32720976Smckusick {
32820976Smckusick 	register struct tty *tp;
32937606Smarc 	register creg, c;
33020976Smckusick 	register struct dhudevice *addr;
33120976Smckusick 	register struct tty *tp0;
33220976Smckusick 	register struct uba_device *ui;
33320976Smckusick 	register line;
33420976Smckusick 	int overrun = 0;
33520976Smckusick 
33635401Stef #ifdef QBA
33737606Smarc 	(void) spltty();
33827256Skridle #endif
33920976Smckusick 	ui = dhuinfo[dhu];
34020976Smckusick 	if (ui == 0 || ui->ui_alive == 0)
34120976Smckusick 		return;
34220976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
34320976Smckusick 	tp0 = &dhu_tty[dhu<<4];
34420976Smckusick 	/*
34520976Smckusick 	 * Loop fetching characters from the silo for this
34620976Smckusick 	 * dhu until there are no more in the silo.
34720976Smckusick 	 */
34837606Smarc 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
34937606Smarc 		line = DHU_RX_LINE(creg);
35020976Smckusick 		tp = tp0 + line;
35137606Smarc 		c = creg & 0xff;
35237606Smarc 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
35320976Smckusick 			/*
35420976Smckusick 			 * modem changed or diag info
35520976Smckusick 			 */
35637606Smarc 			if (creg & DHU_RB_DIAG) {
35720976Smckusick 				/* decode diagnostic messages */
35820976Smckusick 				continue;
35920976Smckusick 			}
36037606Smarc 			if (creg & DHU_ST_DCD)
36125395Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
36225395Skarels 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
36325395Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36425395Skarels 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
36520976Smckusick 			continue;
36620976Smckusick 		}
36720976Smckusick 		if ((tp->t_state&TS_ISOPEN) == 0) {
36820976Smckusick 			wakeup((caddr_t)&tp->t_rawq);
36920976Smckusick #ifdef PORTSELECTOR
37020976Smckusick 			if ((tp->t_state&TS_WOPEN) == 0)
37120976Smckusick #endif
37225395Skarels 				continue;
37320976Smckusick 		}
374*39061Smarc 		if (creg & DHU_RB_PE)
375*39061Smarc 			c |= TTY_PE;
376*39061Smarc 		if (creg & DHU_RB_DO && overrun == 0) {
377*39061Smarc 			log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
378*39061Smarc 			overrun = 1;
37920976Smckusick 		}
380*39061Smarc 		if (creg & DHU_RB_FE)
381*39061Smarc 			c |= TTY_FE;
38237606Smarc 
383*39061Smarc 		(*linesw[tp->t_line].l_rint)(c, tp);
38420976Smckusick 	}
38520976Smckusick }
38620976Smckusick 
38720976Smckusick /*
38820976Smckusick  * Ioctl for DHU11.
38920976Smckusick  */
39020976Smckusick /*ARGSUSED*/
39120976Smckusick dhuioctl(dev, cmd, data, flag)
39220976Smckusick 	caddr_t data;
39320976Smckusick {
39420976Smckusick 	register struct tty *tp;
39520976Smckusick 	register int unit = UNIT(dev);
39620976Smckusick 	int error;
39720976Smckusick 
39820976Smckusick 	tp = &dhu_tty[unit];
39920976Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
40020976Smckusick 	if (error >= 0)
40120976Smckusick 		return (error);
40220976Smckusick 	error = ttioctl(tp, cmd, data, flag);
40337606Smarc 	if (error >= 0)
40420976Smckusick 		return (error);
40520976Smckusick 
40620976Smckusick 	switch (cmd) {
40720976Smckusick 	case TIOCSBRK:
40820976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIS);
40920976Smckusick 		break;
41020976Smckusick 
41120976Smckusick 	case TIOCCBRK:
41220976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIC);
41320976Smckusick 		break;
41420976Smckusick 
41520976Smckusick 	case TIOCSDTR:
41620976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
41720976Smckusick 		break;
41820976Smckusick 
41920976Smckusick 	case TIOCCDTR:
42020976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
42120976Smckusick 		break;
42220976Smckusick 
42320976Smckusick 	case TIOCMSET:
42420976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
42520976Smckusick 		break;
42620976Smckusick 
42720976Smckusick 	case TIOCMBIS:
42820976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
42920976Smckusick 		break;
43020976Smckusick 
43120976Smckusick 	case TIOCMBIC:
43220976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
43320976Smckusick 		break;
43420976Smckusick 
43520976Smckusick 	case TIOCMGET:
43620976Smckusick 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
43720976Smckusick 		break;
43820976Smckusick 	default:
43920976Smckusick 		return (ENOTTY);
44020976Smckusick 	}
44120976Smckusick 	return (0);
44220976Smckusick }
44320976Smckusick 
44420976Smckusick dmtodhu(bits)
44520976Smckusick 	register int bits;
44620976Smckusick {
44720976Smckusick 	register int b = 0;
44820976Smckusick 
44920976Smckusick 	if (bits & DML_RTS) b |= DHU_RTS;
45020976Smckusick 	if (bits & DML_DTR) b |= DHU_DTR;
45120976Smckusick 	if (bits & DML_LE) b |= DHU_LE;
45220976Smckusick 	return(b);
45320976Smckusick }
45420976Smckusick 
45520976Smckusick dhutodm(bits)
45620976Smckusick 	register int bits;
45720976Smckusick {
45820976Smckusick 	register int b = 0;
45920976Smckusick 
46020976Smckusick 	if (bits & DHU_DSR) b |= DML_DSR;
46120976Smckusick 	if (bits & DHU_RNG) b |= DML_RNG;
46220976Smckusick 	if (bits & DHU_CAR) b |= DML_CAR;
46320976Smckusick 	if (bits & DHU_CTS) b |= DML_CTS;
46420976Smckusick 	if (bits & DHU_RTS) b |= DML_RTS;
46520976Smckusick 	if (bits & DHU_DTR) b |= DML_DTR;
46620976Smckusick 	if (bits & DHU_LE) b |= DML_LE;
46720976Smckusick 	return(b);
46820976Smckusick }
46920976Smckusick 
47020976Smckusick 
47120976Smckusick /*
47220976Smckusick  * Set parameters from open or stty into the DHU hardware
47337606Smarc  * registers.  Impossible values for speed or character
47437606Smarc  * size are ignored and not copied back into tp.
47520976Smckusick  */
47637606Smarc dhuparam(tp, want)
47737606Smarc 	register struct tty *tp;
47837606Smarc 	register struct termios *want;
47920976Smckusick {
48037606Smarc 	register int unit = UNIT(tp->t_dev);
48137606Smarc 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
48220976Smckusick 	register int lpar;
48337606Smarc 	register long cflag;
48437606Smarc 	register int incode, outcode;
48520976Smckusick 	int s;
48637606Smarc 
48720976Smckusick 	/*
48820976Smckusick 	 * Block interrupts so parameters will be set
48920976Smckusick 	 * before the line interrupts.
49020976Smckusick 	 */
49137606Smarc 	s = spltty();
49237606Smarc 
49337606Smarc 	if (want->c_ospeed == 0) {
49437606Smarc 		tp->t_ospeed = 0;
49537606Smarc 		tp->t_cflag |= HUPCL;
49620976Smckusick 		(void)dhumctl(unit, DHU_OFF, DMSET);
49720976Smckusick 		splx(s);
49820976Smckusick 		return;
49920976Smckusick 	}
50037606Smarc 
50137606Smarc 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
50237606Smarc 		tp->t_ospeed = want->c_ospeed;
50337606Smarc 	else
50437606Smarc 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
50537606Smarc 
50637606Smarc 	if (want->c_ispeed == 0) {
50737606Smarc 		tp->t_ispeed = 0;
50837606Smarc 		incode = outcode;
50937606Smarc 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
51037606Smarc 		tp->t_ispeed = want->c_ispeed;
51137606Smarc 	else
51237606Smarc 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
51337606Smarc 
51437606Smarc 	lpar = ((char)outcode<<12) | ((char)incode<<8);
51537606Smarc 
51637606Smarc 	switch (want->c_cflag&CSIZE) {
51737606Smarc 	case CS6: case CS7: case CS8:
51837606Smarc 		tp->t_cflag =  want->c_cflag;
51937606Smarc 		break;
52037606Smarc 	default:
52137606Smarc 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
52237606Smarc 	}
52337606Smarc 	cflag = tp->t_cflag;
52437606Smarc 
52537606Smarc 	switch(cflag&CSIZE) {
52637606Smarc 	case CS6:
52737606Smarc 		lpar |= DHU_LP_BITS6;
52837606Smarc 		break;
52937606Smarc 	case CS7:
53037606Smarc 		lpar |= DHU_LP_BITS7;
53137606Smarc 		break;
53237606Smarc 	case CS8:
53320976Smckusick 		lpar |= DHU_LP_BITS8;
53437606Smarc 		break;
53537606Smarc 	}
53637606Smarc 	if (cflag&PARENB) {
53737606Smarc 		lpar |= DHU_LP_PENABLE;
53837606Smarc 		if ((cflag&PARODD) == 0)
53937606Smarc 			lpar |= DHU_LP_EPAR;
54037606Smarc 	}
54137606Smarc 	if (cflag&CSTOPB)
54237606Smarc 		lpar |= DHU_LP_TWOSB;
54337606Smarc 
544*39061Smarc 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
54520976Smckusick 	addr->dhulpr = lpar;
54620976Smckusick 	splx(s);
54720976Smckusick }
54820976Smckusick 
54920976Smckusick /*
55020976Smckusick  * DHU11 transmitter interrupt.
55120976Smckusick  * Restart each line which used to be active but has
55220976Smckusick  * terminated transmission since the last interrupt.
55320976Smckusick  */
55420976Smckusick dhuxint(dhu)
55520976Smckusick 	int dhu;
55620976Smckusick {
55720976Smckusick 	register struct tty *tp;
55820976Smckusick 	register struct dhudevice *addr;
55920976Smckusick 	register struct tty *tp0;
56020976Smckusick 	register struct uba_device *ui;
56120976Smckusick 	register int line, t;
56220976Smckusick 	u_short cntr;
56320976Smckusick 
56435401Stef #ifdef QBA
56527256Skridle 	(void) spl5();
56627256Skridle #endif
56720976Smckusick 	ui = dhuinfo[dhu];
56820976Smckusick 	tp0 = &dhu_tty[dhu<<4];
56920976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
57020976Smckusick 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
57120976Smckusick 		line = DHU_TX_LINE(t);
57220976Smckusick 		tp = tp0 + line;
57320976Smckusick 		tp->t_state &= ~TS_BUSY;
57420976Smckusick 		if (t & DHU_CSH_NXM) {
57520976Smckusick 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
57620976Smckusick 			/* SHOULD RESTART OR SOMETHING... */
57720976Smckusick 		}
57820976Smckusick 		if (tp->t_state&TS_FLUSH)
57920976Smckusick 			tp->t_state &= ~TS_FLUSH;
58020976Smckusick 		else {
58120976Smckusick 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
58220976Smckusick 			/*
58320976Smckusick 			 * Do arithmetic in a short to make up
58420976Smckusick 			 * for lost 16&17 bits.
58520976Smckusick 			 */
58620976Smckusick 			cntr = addr->dhubar1 -
58720976Smckusick 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
58820976Smckusick 			ndflush(&tp->t_outq, (int)cntr);
58920976Smckusick 		}
59020976Smckusick 		if (tp->t_line)
59120976Smckusick 			(*linesw[tp->t_line].l_start)(tp);
59220976Smckusick 		else
59320976Smckusick 			dhustart(tp);
59420976Smckusick 	}
59520976Smckusick }
59620976Smckusick 
59720976Smckusick /*
59820976Smckusick  * Start (restart) transmission on the given DHU11 line.
59920976Smckusick  */
60020976Smckusick dhustart(tp)
60120976Smckusick 	register struct tty *tp;
60220976Smckusick {
60320976Smckusick 	register struct dhudevice *addr;
60420976Smckusick 	register int car, dhu, unit, nch;
60520976Smckusick 	int s;
60620976Smckusick 
60720976Smckusick 	unit = minor(tp->t_dev);
60820976Smckusick 	dhu = unit >> 4;
60920976Smckusick 	unit &= 0xf;
61020976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
61120976Smckusick 
61220976Smckusick 	/*
61320976Smckusick 	 * Must hold interrupts in following code to prevent
61420976Smckusick 	 * state of the tp from changing.
61520976Smckusick 	 */
61620976Smckusick 	s = spl5();
61720976Smckusick 	/*
61820976Smckusick 	 * If it's currently active, or delaying, no need to do anything.
61920976Smckusick 	 */
62020976Smckusick 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
62120976Smckusick 		goto out;
62220976Smckusick 	/*
62320976Smckusick 	 * If there are sleepers, and output has drained below low
62420976Smckusick 	 * water mark, wake up the sleepers..
62520976Smckusick 	 */
62637606Smarc 	if (tp->t_outq.c_cc <= tp->t_lowat) {
62720976Smckusick 		if (tp->t_state&TS_ASLEEP) {
62820976Smckusick 			tp->t_state &= ~TS_ASLEEP;
62920976Smckusick 			wakeup((caddr_t)&tp->t_outq);
63020976Smckusick 		}
63120976Smckusick 		if (tp->t_wsel) {
63220976Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
63320976Smckusick 			tp->t_wsel = 0;
63420976Smckusick 			tp->t_state &= ~TS_WCOLL;
63520976Smckusick 		}
63620976Smckusick 	}
63720976Smckusick 	/*
63820976Smckusick 	 * Now restart transmission unless the output queue is
63920976Smckusick 	 * empty.
64020976Smckusick 	 */
64120976Smckusick 	if (tp->t_outq.c_cc == 0)
64220976Smckusick 		goto out;
643*39061Smarc 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
64420976Smckusick 		nch = ndqb(&tp->t_outq, 0);
64520976Smckusick 	else {
64620976Smckusick 		nch = ndqb(&tp->t_outq, 0200);
64720976Smckusick 		/*
64820976Smckusick 		 * If first thing on queue is a delay process it.
64920976Smckusick 		 */
65020976Smckusick 		if (nch == 0) {
65120976Smckusick 			nch = getc(&tp->t_outq);
65220976Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
65320976Smckusick 			tp->t_state |= TS_TIMEOUT;
65420976Smckusick 			goto out;
65520976Smckusick 		}
65620976Smckusick 	}
65720976Smckusick 	/*
65820976Smckusick 	 * If characters to transmit, restart transmission.
65920976Smckusick 	 */
66020976Smckusick 	if (nch) {
66120976Smckusick 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
66220976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
66320976Smckusick 		addr->dhulcr &= ~DHU_LC_TXABORT;
66420976Smckusick 		addr->dhubcr = nch;
66520976Smckusick 		addr->dhubar1 = car;
66620976Smckusick 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
66720976Smckusick 					DHU_BA2_DMAGO;
66820976Smckusick 		tp->t_state |= TS_BUSY;
66920976Smckusick 	}
67020976Smckusick out:
67120976Smckusick 	splx(s);
67220976Smckusick }
67320976Smckusick 
67420976Smckusick /*
67520976Smckusick  * Stop output on a line, e.g. for ^S/^Q or output flush.
67620976Smckusick  */
67720976Smckusick /*ARGSUSED*/
67820976Smckusick dhustop(tp, flag)
67920976Smckusick 	register struct tty *tp;
68020976Smckusick {
68120976Smckusick 	register struct dhudevice *addr;
68220976Smckusick 	register int unit, s;
68320976Smckusick 
68420976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
68520976Smckusick 	/*
68620976Smckusick 	 * Block input/output interrupts while messing with state.
68720976Smckusick 	 */
68820976Smckusick 	s = spl5();
68920976Smckusick 	if (tp->t_state & TS_BUSY) {
69020976Smckusick 		/*
69120976Smckusick 		 * Device is transmitting; stop output
69220976Smckusick 		 * by selecting the line and setting the
69320976Smckusick 		 * abort xmit bit.  We will get an xmit interrupt,
69420976Smckusick 		 * where we will figure out where to continue the
69520976Smckusick 		 * next time the transmitter is enabled.  If
69620976Smckusick 		 * TS_FLUSH is set, the outq will be flushed.
69720976Smckusick 		 * In either case, dhustart will clear the TXABORT bit.
69820976Smckusick 		 */
69920976Smckusick 		unit = minor(tp->t_dev);
70020976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
70120976Smckusick 		addr->dhulcr |= DHU_LC_TXABORT;
70220976Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
70320976Smckusick 			tp->t_state |= TS_FLUSH;
70420976Smckusick 	}
70520976Smckusick 	(void) splx(s);
70620976Smckusick }
70720976Smckusick 
70820976Smckusick /*
70920976Smckusick  * DHU11 modem control
71020976Smckusick  */
71120976Smckusick dhumctl(dev, bits, how)
71220976Smckusick 	dev_t dev;
71320976Smckusick 	int bits, how;
71420976Smckusick {
71520976Smckusick 	register struct dhudevice *dhuaddr;
71626291Skarels 	register int unit, mbits;
71720976Smckusick 	int s;
71820976Smckusick 
71920976Smckusick 	unit = UNIT(dev);
72020976Smckusick 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
72120976Smckusick 	unit &= 0xf;
72220976Smckusick 	s = spl5();
72320976Smckusick 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
72420976Smckusick 	/*
72520976Smckusick 	 * combine byte from stat register (read only, bits 16..23)
72620976Smckusick 	 * with lcr register (read write, bits 0..15).
72720976Smckusick 	 */
72820976Smckusick 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
72920976Smckusick 	switch (how) {
73020976Smckusick 	case DMSET:
73120976Smckusick 		mbits = (mbits & 0xff0000) | bits;
73220976Smckusick 		break;
73320976Smckusick 
73420976Smckusick 	case DMBIS:
73520976Smckusick 		mbits |= bits;
73620976Smckusick 		break;
73720976Smckusick 
73820976Smckusick 	case DMBIC:
73920976Smckusick 		mbits &= ~bits;
74020976Smckusick 		break;
74120976Smckusick 
74220976Smckusick 	case DMGET:
74320976Smckusick 		(void) splx(s);
74420976Smckusick 		return(mbits);
74520976Smckusick 	}
74620976Smckusick 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
74720976Smckusick 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
74820976Smckusick 	(void) splx(s);
74920976Smckusick 	return(mbits);
75020976Smckusick }
75120976Smckusick 
75220976Smckusick /*
75320976Smckusick  * Reset state of driver if UBA reset was necessary.
75420976Smckusick  * Reset the line and modem control registers.
75520976Smckusick  * restart transmitters.
75620976Smckusick  */
75720976Smckusick dhureset(uban)
75820976Smckusick 	int uban;
75920976Smckusick {
76020976Smckusick 	register int dhu, unit;
76120976Smckusick 	register struct tty *tp;
76220976Smckusick 	register struct uba_device *ui;
76320976Smckusick 	register struct dhudevice *addr;
76420976Smckusick 	int i;
76520976Smckusick 
76620976Smckusick 	for (dhu = 0; dhu < NDHU; dhu++) {
76720976Smckusick 		ui = dhuinfo[dhu];
76820976Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
76920976Smckusick 			continue;
77020976Smckusick 		printf(" dhu%d", dhu);
77130322Skarels 		if (dhu_uballoc[uban] == dhu) {
77230322Skarels 			int info;
77330322Skarels 
77430322Skarels 			info = uballoc(uban, (caddr_t)cfree,
77530322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
77630322Skarels 			if (info)
77730322Skarels 				cbase[uban] = UBAI_ADDR(info);
77830322Skarels 			else {
77930322Skarels 				printf(" [can't get uba map]");
78030322Skarels 				cbase[uban] = -1;
78130322Skarels 			}
78225434Skarels 		}
78320976Smckusick 		addr = (struct dhudevice *)ui->ui_addr;
78420976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
78520976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
78620976Smckusick 		unit = dhu * 16;
78720976Smckusick 		for (i = 0; i < 16; i++) {
78820976Smckusick 			tp = &dhu_tty[unit];
78920976Smckusick 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
79037606Smarc 				dhuparam(tp, &tp->t_termios);
79120976Smckusick 				(void)dhumctl(unit, DHU_ON, DMSET);
79220976Smckusick 				tp->t_state &= ~TS_BUSY;
79320976Smckusick 				dhustart(tp);
79420976Smckusick 			}
79520976Smckusick 			unit++;
79620976Smckusick 		}
79720976Smckusick 	}
79820976Smckusick }
79920976Smckusick #endif
800