xref: /csrg-svn/sys/vax/uba/dhu.c (revision 40729)
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*40729Skarels  *	@(#)dhu.c	7.10 (Berkeley) 04/03/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  */
2237514Smckusick #include "machine/pte.h"
2320976Smckusick 
2420976Smckusick #include "param.h"
2520976Smckusick #include "conf.h"
2620976Smckusick #include "user.h"
2720976Smckusick #include "proc.h"
2820976Smckusick #include "ioctl.h"
2920976Smckusick #include "tty.h"
3037606Smarc #include "ttydefaults.h"
3120976Smckusick #include "map.h"
3220976Smckusick #include "buf.h"
3320976Smckusick #include "vm.h"
3420976Smckusick #include "kernel.h"
3520976Smckusick #include "syslog.h"
3620976Smckusick 
3720976Smckusick #include "uba.h"
3820976Smckusick #include "ubareg.h"
3920976Smckusick #include "ubavar.h"
4020976Smckusick #include "dhureg.h"
4120976Smckusick 
4220976Smckusick #include "bkmac.h"
4320976Smckusick #include "clist.h"
4420976Smckusick #include "file.h"
4520976Smckusick #include "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;
200*40729Skarels 	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) {
23520976Smckusick 		ttychars(tp);
23620976Smckusick #ifndef PORTSELECTOR
23737606Smarc 		if (tp->t_ospeed == 0) {
23837606Smarc #endif
23937606Smarc 			tp->t_ispeed = SPEED;
24037606Smarc 			tp->t_ospeed = SPEED;
24137606Smarc 			ttsetwater(tp);
24237606Smarc 			tp->t_iflag = TTYDEF_IFLAG;
24337606Smarc 			tp->t_oflag = TTYDEF_OFLAG;
24437606Smarc 			tp->t_lflag = LFLAG;
24537606Smarc 			tp->t_cflag = TTYDEF_CFLAG;
24637606Smarc #ifdef PORTSELECTOR
24737606Smarc 			tp->t_cflag |= HUPCL;
24837606Smarc #else
24920976Smckusick 		}
25037606Smarc #endif
25120976Smckusick 		tp->t_dev = dev;
25237606Smarc 		dhuparam(tp, &tp->t_termios);
25320976Smckusick 	}
25420976Smckusick 	/*
25520976Smckusick 	 * Wait for carrier, then process line discipline specific open.
25620976Smckusick 	 */
25737606Smarc 	s = spltty();
25820976Smckusick 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
25920976Smckusick 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
26020976Smckusick 		tp->t_state |= TS_CARR_ON;
261*40729Skarels 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
262*40729Skarels 	    (tp->t_state & TS_CARR_ON) == 0) {
26320976Smckusick 		tp->t_state |= TS_WOPEN;
264*40729Skarels 		if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
265*40729Skarels 		    ttopen, 0))
266*40729Skarels 			break;
26720976Smckusick 	}
26820976Smckusick 	(void) splx(s);
269*40729Skarels 	if (error)
270*40729Skarels 		return (error);
27120976Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
27220976Smckusick }
27320976Smckusick 
27420976Smckusick /*
27520976Smckusick  * Close a DHU11 line, turning off the modem control.
27620976Smckusick  */
27720976Smckusick /*ARGSUSED*/
27820976Smckusick dhuclose(dev, flag)
27920976Smckusick 	dev_t dev;
28020976Smckusick 	int flag;
28120976Smckusick {
28220976Smckusick 	register struct tty *tp;
28320976Smckusick 	register unit;
28420976Smckusick 
28520976Smckusick 	unit = UNIT(dev);
28620976Smckusick 	tp = &dhu_tty[unit];
28720976Smckusick 	(*linesw[tp->t_line].l_close)(tp);
28820976Smckusick 	(void) dhumctl(unit, DHU_BRK, DMBIC);
28937606Smarc 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
290*40729Skarels 	    (tp->t_state&TS_ISOPEN) == 0) {
29120976Smckusick #ifdef PORTSELECTOR
29220976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29320976Smckusick 		/* Hold DTR low for 0.5 seconds */
294*40729Skarels 		(void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2);
29520976Smckusick #else
29620976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
29720976Smckusick #endif PORTSELECTOR
298*40729Skarels 	}
299*40729Skarels 	return (ttyclose(tp));
30020976Smckusick }
30120976Smckusick 
30239061Smarc dhuread(dev, uio, flag)
30320976Smckusick 	dev_t dev;
30420976Smckusick 	struct uio *uio;
30520976Smckusick {
30620976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
30720976Smckusick 
30839061Smarc 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
30920976Smckusick }
31020976Smckusick 
31139061Smarc dhuwrite(dev, uio, flag)
31220976Smckusick 	dev_t dev;
31320976Smckusick 	struct uio *uio;
31420976Smckusick {
31520976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
31620976Smckusick 
31739061Smarc 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
31820976Smckusick }
31920976Smckusick 
32020976Smckusick /*
32120976Smckusick  * DHU11 receiver interrupt.
32220976Smckusick  */
32320976Smckusick dhurint(dhu)
32420976Smckusick 	int dhu;
32520976Smckusick {
32620976Smckusick 	register struct tty *tp;
32737606Smarc 	register creg, c;
32820976Smckusick 	register struct dhudevice *addr;
32920976Smckusick 	register struct tty *tp0;
33020976Smckusick 	register struct uba_device *ui;
33120976Smckusick 	register line;
33220976Smckusick 	int overrun = 0;
33320976Smckusick 
33435401Stef #ifdef QBA
33537606Smarc 	(void) spltty();
33627256Skridle #endif
33720976Smckusick 	ui = dhuinfo[dhu];
33820976Smckusick 	if (ui == 0 || ui->ui_alive == 0)
33920976Smckusick 		return;
34020976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
34120976Smckusick 	tp0 = &dhu_tty[dhu<<4];
34220976Smckusick 	/*
34320976Smckusick 	 * Loop fetching characters from the silo for this
34420976Smckusick 	 * dhu until there are no more in the silo.
34520976Smckusick 	 */
34637606Smarc 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
34737606Smarc 		line = DHU_RX_LINE(creg);
34820976Smckusick 		tp = tp0 + line;
34937606Smarc 		c = creg & 0xff;
35037606Smarc 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
35120976Smckusick 			/*
35220976Smckusick 			 * modem changed or diag info
35320976Smckusick 			 */
35437606Smarc 			if (creg & DHU_RB_DIAG) {
35520976Smckusick 				/* decode diagnostic messages */
35620976Smckusick 				continue;
35720976Smckusick 			}
35837606Smarc 			if (creg & DHU_ST_DCD)
35925395Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
36025395Skarels 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
36125395Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
36225395Skarels 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
36320976Smckusick 			continue;
36420976Smckusick 		}
36520976Smckusick 		if ((tp->t_state&TS_ISOPEN) == 0) {
36620976Smckusick 			wakeup((caddr_t)&tp->t_rawq);
36720976Smckusick #ifdef PORTSELECTOR
36820976Smckusick 			if ((tp->t_state&TS_WOPEN) == 0)
36920976Smckusick #endif
37025395Skarels 				continue;
37120976Smckusick 		}
37239061Smarc 		if (creg & DHU_RB_PE)
37339061Smarc 			c |= TTY_PE;
37439061Smarc 		if (creg & DHU_RB_DO && overrun == 0) {
37539061Smarc 			log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
37639061Smarc 			overrun = 1;
37720976Smckusick 		}
37839061Smarc 		if (creg & DHU_RB_FE)
37939061Smarc 			c |= TTY_FE;
38037606Smarc 
38139061Smarc 		(*linesw[tp->t_line].l_rint)(c, tp);
38220976Smckusick 	}
38320976Smckusick }
38420976Smckusick 
38520976Smckusick /*
38620976Smckusick  * Ioctl for DHU11.
38720976Smckusick  */
38820976Smckusick /*ARGSUSED*/
38920976Smckusick dhuioctl(dev, cmd, data, flag)
39020976Smckusick 	caddr_t data;
39120976Smckusick {
39220976Smckusick 	register struct tty *tp;
39320976Smckusick 	register int unit = UNIT(dev);
39420976Smckusick 	int error;
39520976Smckusick 
39620976Smckusick 	tp = &dhu_tty[unit];
39720976Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
39820976Smckusick 	if (error >= 0)
39920976Smckusick 		return (error);
40020976Smckusick 	error = ttioctl(tp, cmd, data, flag);
40137606Smarc 	if (error >= 0)
40220976Smckusick 		return (error);
40320976Smckusick 
40420976Smckusick 	switch (cmd) {
40520976Smckusick 	case TIOCSBRK:
40620976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIS);
40720976Smckusick 		break;
40820976Smckusick 
40920976Smckusick 	case TIOCCBRK:
41020976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIC);
41120976Smckusick 		break;
41220976Smckusick 
41320976Smckusick 	case TIOCSDTR:
41420976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
41520976Smckusick 		break;
41620976Smckusick 
41720976Smckusick 	case TIOCCDTR:
41820976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
41920976Smckusick 		break;
42020976Smckusick 
42120976Smckusick 	case TIOCMSET:
42220976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
42320976Smckusick 		break;
42420976Smckusick 
42520976Smckusick 	case TIOCMBIS:
42620976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
42720976Smckusick 		break;
42820976Smckusick 
42920976Smckusick 	case TIOCMBIC:
43020976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
43120976Smckusick 		break;
43220976Smckusick 
43320976Smckusick 	case TIOCMGET:
43420976Smckusick 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
43520976Smckusick 		break;
43620976Smckusick 	default:
43720976Smckusick 		return (ENOTTY);
43820976Smckusick 	}
43920976Smckusick 	return (0);
44020976Smckusick }
44120976Smckusick 
44220976Smckusick dmtodhu(bits)
44320976Smckusick 	register int bits;
44420976Smckusick {
44520976Smckusick 	register int b = 0;
44620976Smckusick 
44720976Smckusick 	if (bits & DML_RTS) b |= DHU_RTS;
44820976Smckusick 	if (bits & DML_DTR) b |= DHU_DTR;
44920976Smckusick 	if (bits & DML_LE) b |= DHU_LE;
45020976Smckusick 	return(b);
45120976Smckusick }
45220976Smckusick 
45320976Smckusick dhutodm(bits)
45420976Smckusick 	register int bits;
45520976Smckusick {
45620976Smckusick 	register int b = 0;
45720976Smckusick 
45820976Smckusick 	if (bits & DHU_DSR) b |= DML_DSR;
45920976Smckusick 	if (bits & DHU_RNG) b |= DML_RNG;
46020976Smckusick 	if (bits & DHU_CAR) b |= DML_CAR;
46120976Smckusick 	if (bits & DHU_CTS) b |= DML_CTS;
46220976Smckusick 	if (bits & DHU_RTS) b |= DML_RTS;
46320976Smckusick 	if (bits & DHU_DTR) b |= DML_DTR;
46420976Smckusick 	if (bits & DHU_LE) b |= DML_LE;
46520976Smckusick 	return(b);
46620976Smckusick }
46720976Smckusick 
46820976Smckusick 
46920976Smckusick /*
47020976Smckusick  * Set parameters from open or stty into the DHU hardware
47137606Smarc  * registers.  Impossible values for speed or character
47237606Smarc  * size are ignored and not copied back into tp.
47320976Smckusick  */
47437606Smarc dhuparam(tp, want)
47537606Smarc 	register struct tty *tp;
47637606Smarc 	register struct termios *want;
47720976Smckusick {
47837606Smarc 	register int unit = UNIT(tp->t_dev);
47937606Smarc 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
48020976Smckusick 	register int lpar;
48137606Smarc 	register long cflag;
48237606Smarc 	register int incode, outcode;
48320976Smckusick 	int s;
48437606Smarc 
48520976Smckusick 	/*
48620976Smckusick 	 * Block interrupts so parameters will be set
48720976Smckusick 	 * before the line interrupts.
48820976Smckusick 	 */
48937606Smarc 	s = spltty();
49037606Smarc 
49137606Smarc 	if (want->c_ospeed == 0) {
49237606Smarc 		tp->t_ospeed = 0;
49337606Smarc 		tp->t_cflag |= HUPCL;
49420976Smckusick 		(void)dhumctl(unit, DHU_OFF, DMSET);
49520976Smckusick 		splx(s);
49620976Smckusick 		return;
49720976Smckusick 	}
49837606Smarc 
49937606Smarc 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
50037606Smarc 		tp->t_ospeed = want->c_ospeed;
50137606Smarc 	else
50237606Smarc 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
50337606Smarc 
50437606Smarc 	if (want->c_ispeed == 0) {
50537606Smarc 		tp->t_ispeed = 0;
50637606Smarc 		incode = outcode;
50737606Smarc 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
50837606Smarc 		tp->t_ispeed = want->c_ispeed;
50937606Smarc 	else
51037606Smarc 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
51137606Smarc 
51237606Smarc 	lpar = ((char)outcode<<12) | ((char)incode<<8);
51337606Smarc 
51437606Smarc 	switch (want->c_cflag&CSIZE) {
51537606Smarc 	case CS6: case CS7: case CS8:
51637606Smarc 		tp->t_cflag =  want->c_cflag;
51737606Smarc 		break;
51837606Smarc 	default:
51937606Smarc 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
52037606Smarc 	}
52137606Smarc 	cflag = tp->t_cflag;
52237606Smarc 
52337606Smarc 	switch(cflag&CSIZE) {
52437606Smarc 	case CS6:
52537606Smarc 		lpar |= DHU_LP_BITS6;
52637606Smarc 		break;
52737606Smarc 	case CS7:
52837606Smarc 		lpar |= DHU_LP_BITS7;
52937606Smarc 		break;
53037606Smarc 	case CS8:
53120976Smckusick 		lpar |= DHU_LP_BITS8;
53237606Smarc 		break;
53337606Smarc 	}
53437606Smarc 	if (cflag&PARENB) {
53537606Smarc 		lpar |= DHU_LP_PENABLE;
53637606Smarc 		if ((cflag&PARODD) == 0)
53737606Smarc 			lpar |= DHU_LP_EPAR;
53837606Smarc 	}
53937606Smarc 	if (cflag&CSTOPB)
54037606Smarc 		lpar |= DHU_LP_TWOSB;
54137606Smarc 
54239061Smarc 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
54320976Smckusick 	addr->dhulpr = lpar;
54420976Smckusick 	splx(s);
54520976Smckusick }
54620976Smckusick 
54720976Smckusick /*
54820976Smckusick  * DHU11 transmitter interrupt.
54920976Smckusick  * Restart each line which used to be active but has
55020976Smckusick  * terminated transmission since the last interrupt.
55120976Smckusick  */
55220976Smckusick dhuxint(dhu)
55320976Smckusick 	int dhu;
55420976Smckusick {
55520976Smckusick 	register struct tty *tp;
55620976Smckusick 	register struct dhudevice *addr;
55720976Smckusick 	register struct tty *tp0;
55820976Smckusick 	register struct uba_device *ui;
55920976Smckusick 	register int line, t;
56020976Smckusick 	u_short cntr;
56120976Smckusick 
56235401Stef #ifdef QBA
56327256Skridle 	(void) spl5();
56427256Skridle #endif
56520976Smckusick 	ui = dhuinfo[dhu];
56620976Smckusick 	tp0 = &dhu_tty[dhu<<4];
56720976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
56820976Smckusick 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
56920976Smckusick 		line = DHU_TX_LINE(t);
57020976Smckusick 		tp = tp0 + line;
57120976Smckusick 		tp->t_state &= ~TS_BUSY;
57220976Smckusick 		if (t & DHU_CSH_NXM) {
57320976Smckusick 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
57420976Smckusick 			/* SHOULD RESTART OR SOMETHING... */
57520976Smckusick 		}
57620976Smckusick 		if (tp->t_state&TS_FLUSH)
57720976Smckusick 			tp->t_state &= ~TS_FLUSH;
57820976Smckusick 		else {
57920976Smckusick 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
58020976Smckusick 			/*
58120976Smckusick 			 * Do arithmetic in a short to make up
58220976Smckusick 			 * for lost 16&17 bits.
58320976Smckusick 			 */
58420976Smckusick 			cntr = addr->dhubar1 -
58520976Smckusick 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
58620976Smckusick 			ndflush(&tp->t_outq, (int)cntr);
58720976Smckusick 		}
58820976Smckusick 		if (tp->t_line)
58920976Smckusick 			(*linesw[tp->t_line].l_start)(tp);
59020976Smckusick 		else
59120976Smckusick 			dhustart(tp);
59220976Smckusick 	}
59320976Smckusick }
59420976Smckusick 
59520976Smckusick /*
59620976Smckusick  * Start (restart) transmission on the given DHU11 line.
59720976Smckusick  */
59820976Smckusick dhustart(tp)
59920976Smckusick 	register struct tty *tp;
60020976Smckusick {
60120976Smckusick 	register struct dhudevice *addr;
60220976Smckusick 	register int car, dhu, unit, nch;
60320976Smckusick 	int s;
60420976Smckusick 
60520976Smckusick 	unit = minor(tp->t_dev);
60620976Smckusick 	dhu = unit >> 4;
60720976Smckusick 	unit &= 0xf;
60820976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
60920976Smckusick 
61020976Smckusick 	/*
61120976Smckusick 	 * Must hold interrupts in following code to prevent
61220976Smckusick 	 * state of the tp from changing.
61320976Smckusick 	 */
61420976Smckusick 	s = spl5();
61520976Smckusick 	/*
61620976Smckusick 	 * If it's currently active, or delaying, no need to do anything.
61720976Smckusick 	 */
61820976Smckusick 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
61920976Smckusick 		goto out;
62020976Smckusick 	/*
62120976Smckusick 	 * If there are sleepers, and output has drained below low
62220976Smckusick 	 * water mark, wake up the sleepers..
62320976Smckusick 	 */
62437606Smarc 	if (tp->t_outq.c_cc <= tp->t_lowat) {
62520976Smckusick 		if (tp->t_state&TS_ASLEEP) {
62620976Smckusick 			tp->t_state &= ~TS_ASLEEP;
62720976Smckusick 			wakeup((caddr_t)&tp->t_outq);
62820976Smckusick 		}
62920976Smckusick 		if (tp->t_wsel) {
63020976Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
63120976Smckusick 			tp->t_wsel = 0;
63220976Smckusick 			tp->t_state &= ~TS_WCOLL;
63320976Smckusick 		}
63420976Smckusick 	}
63520976Smckusick 	/*
63620976Smckusick 	 * Now restart transmission unless the output queue is
63720976Smckusick 	 * empty.
63820976Smckusick 	 */
63920976Smckusick 	if (tp->t_outq.c_cc == 0)
64020976Smckusick 		goto out;
64139061Smarc 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
64220976Smckusick 		nch = ndqb(&tp->t_outq, 0);
64320976Smckusick 	else {
64420976Smckusick 		nch = ndqb(&tp->t_outq, 0200);
64520976Smckusick 		/*
64620976Smckusick 		 * If first thing on queue is a delay process it.
64720976Smckusick 		 */
64820976Smckusick 		if (nch == 0) {
64920976Smckusick 			nch = getc(&tp->t_outq);
65020976Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
65120976Smckusick 			tp->t_state |= TS_TIMEOUT;
65220976Smckusick 			goto out;
65320976Smckusick 		}
65420976Smckusick 	}
65520976Smckusick 	/*
65620976Smckusick 	 * If characters to transmit, restart transmission.
65720976Smckusick 	 */
65820976Smckusick 	if (nch) {
65920976Smckusick 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
66020976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
66120976Smckusick 		addr->dhulcr &= ~DHU_LC_TXABORT;
66220976Smckusick 		addr->dhubcr = nch;
66320976Smckusick 		addr->dhubar1 = car;
66420976Smckusick 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
66520976Smckusick 					DHU_BA2_DMAGO;
66620976Smckusick 		tp->t_state |= TS_BUSY;
66720976Smckusick 	}
66820976Smckusick out:
66920976Smckusick 	splx(s);
67020976Smckusick }
67120976Smckusick 
67220976Smckusick /*
67320976Smckusick  * Stop output on a line, e.g. for ^S/^Q or output flush.
67420976Smckusick  */
67520976Smckusick /*ARGSUSED*/
67620976Smckusick dhustop(tp, flag)
67720976Smckusick 	register struct tty *tp;
67820976Smckusick {
67920976Smckusick 	register struct dhudevice *addr;
68020976Smckusick 	register int unit, s;
68120976Smckusick 
68220976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
68320976Smckusick 	/*
68420976Smckusick 	 * Block input/output interrupts while messing with state.
68520976Smckusick 	 */
68620976Smckusick 	s = spl5();
68720976Smckusick 	if (tp->t_state & TS_BUSY) {
68820976Smckusick 		/*
68920976Smckusick 		 * Device is transmitting; stop output
69020976Smckusick 		 * by selecting the line and setting the
69120976Smckusick 		 * abort xmit bit.  We will get an xmit interrupt,
69220976Smckusick 		 * where we will figure out where to continue the
69320976Smckusick 		 * next time the transmitter is enabled.  If
69420976Smckusick 		 * TS_FLUSH is set, the outq will be flushed.
69520976Smckusick 		 * In either case, dhustart will clear the TXABORT bit.
69620976Smckusick 		 */
69720976Smckusick 		unit = minor(tp->t_dev);
69820976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
69920976Smckusick 		addr->dhulcr |= DHU_LC_TXABORT;
70020976Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
70120976Smckusick 			tp->t_state |= TS_FLUSH;
70220976Smckusick 	}
70320976Smckusick 	(void) splx(s);
70420976Smckusick }
70520976Smckusick 
70620976Smckusick /*
70720976Smckusick  * DHU11 modem control
70820976Smckusick  */
70920976Smckusick dhumctl(dev, bits, how)
71020976Smckusick 	dev_t dev;
71120976Smckusick 	int bits, how;
71220976Smckusick {
71320976Smckusick 	register struct dhudevice *dhuaddr;
71426291Skarels 	register int unit, mbits;
71520976Smckusick 	int s;
71620976Smckusick 
71720976Smckusick 	unit = UNIT(dev);
71820976Smckusick 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
71920976Smckusick 	unit &= 0xf;
72020976Smckusick 	s = spl5();
72120976Smckusick 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
72220976Smckusick 	/*
72320976Smckusick 	 * combine byte from stat register (read only, bits 16..23)
72420976Smckusick 	 * with lcr register (read write, bits 0..15).
72520976Smckusick 	 */
72620976Smckusick 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
72720976Smckusick 	switch (how) {
72820976Smckusick 	case DMSET:
72920976Smckusick 		mbits = (mbits & 0xff0000) | bits;
73020976Smckusick 		break;
73120976Smckusick 
73220976Smckusick 	case DMBIS:
73320976Smckusick 		mbits |= bits;
73420976Smckusick 		break;
73520976Smckusick 
73620976Smckusick 	case DMBIC:
73720976Smckusick 		mbits &= ~bits;
73820976Smckusick 		break;
73920976Smckusick 
74020976Smckusick 	case DMGET:
74120976Smckusick 		(void) splx(s);
74220976Smckusick 		return(mbits);
74320976Smckusick 	}
74420976Smckusick 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
74520976Smckusick 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
74620976Smckusick 	(void) splx(s);
74720976Smckusick 	return(mbits);
74820976Smckusick }
74920976Smckusick 
75020976Smckusick /*
75120976Smckusick  * Reset state of driver if UBA reset was necessary.
75220976Smckusick  * Reset the line and modem control registers.
75320976Smckusick  * restart transmitters.
75420976Smckusick  */
75520976Smckusick dhureset(uban)
75620976Smckusick 	int uban;
75720976Smckusick {
75820976Smckusick 	register int dhu, unit;
75920976Smckusick 	register struct tty *tp;
76020976Smckusick 	register struct uba_device *ui;
76120976Smckusick 	register struct dhudevice *addr;
76220976Smckusick 	int i;
76320976Smckusick 
76420976Smckusick 	for (dhu = 0; dhu < NDHU; dhu++) {
76520976Smckusick 		ui = dhuinfo[dhu];
76620976Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
76720976Smckusick 			continue;
76820976Smckusick 		printf(" dhu%d", dhu);
76930322Skarels 		if (dhu_uballoc[uban] == dhu) {
77030322Skarels 			int info;
77130322Skarels 
77230322Skarels 			info = uballoc(uban, (caddr_t)cfree,
77330322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
77430322Skarels 			if (info)
77530322Skarels 				cbase[uban] = UBAI_ADDR(info);
77630322Skarels 			else {
77730322Skarels 				printf(" [can't get uba map]");
77830322Skarels 				cbase[uban] = -1;
77930322Skarels 			}
78025434Skarels 		}
78120976Smckusick 		addr = (struct dhudevice *)ui->ui_addr;
78220976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
78320976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
78420976Smckusick 		unit = dhu * 16;
78520976Smckusick 		for (i = 0; i < 16; i++) {
78620976Smckusick 			tp = &dhu_tty[unit];
78720976Smckusick 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
78837606Smarc 				dhuparam(tp, &tp->t_termios);
78920976Smckusick 				(void)dhumctl(unit, DHU_ON, DMSET);
79020976Smckusick 				tp->t_state &= ~TS_BUSY;
79120976Smckusick 				dhustart(tp);
79220976Smckusick 			}
79320976Smckusick 			unit++;
79420976Smckusick 		}
79520976Smckusick 	}
79620976Smckusick }
79720976Smckusick #endif
798