xref: /csrg-svn/sys/vax/uba/dhu.c (revision 49759)
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*49759Smarc  *	@(#)dhu.c	7.16 (Berkeley) 05/16/91
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  */
2245804Sbostic #include "../include/pte.h"
2320976Smckusick 
2445804Sbostic #include "sys/param.h"
2545804Sbostic #include "sys/conf.h"
2645804Sbostic #include "sys/user.h"
2745804Sbostic #include "sys/proc.h"
2845804Sbostic #include "sys/ioctl.h"
2945804Sbostic #include "sys/tty.h"
3045804Sbostic #include "sys/ttydefaults.h"
3145804Sbostic #include "sys/map.h"
3245804Sbostic #include "sys/buf.h"
3345804Sbostic #include "sys/vm.h"
3445804Sbostic #include "sys/kernel.h"
3545804Sbostic #include "sys/syslog.h"
3620976Smckusick 
3720976Smckusick #include "uba.h"
3820976Smckusick #include "ubareg.h"
3920976Smckusick #include "ubavar.h"
4020976Smckusick #include "dhureg.h"
4120976Smckusick 
4245804Sbostic #include "sys/clist.h"
4345804Sbostic #include "sys/file.h"
4445804Sbostic #include "sys/uio.h"
4520976Smckusick 
4620976Smckusick /*
4720976Smckusick  * Definition of the driver for the auto-configuration program.
4820976Smckusick  */
4920976Smckusick int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
5020976Smckusick struct	uba_device *dhuinfo[NDHU];
5125519Stef u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
5220976Smckusick struct	uba_driver dhudriver =
5320976Smckusick 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
5420976Smckusick 
5520976Smckusick #define	NDHULINE 	(NDHU*16)
5620976Smckusick 
5720976Smckusick #define	UNIT(x)	(minor(x))
5820976Smckusick 
5920976Smckusick #ifndef PORTSELECTOR
6037606Smarc #define SPEED	TTYDEF_SPEED
6137606Smarc #define LFLAG	TTYDEF_LFLAG
6220976Smckusick #else
6337606Smarc #define SPEED	B4800
6437606Smarc #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
6520976Smckusick #endif
6620976Smckusick 
6720976Smckusick /*
6820976Smckusick  * default receive silo timeout value -- valid values are 2..255
6920976Smckusick  * number of ms. to delay between first char received and receive interrupt
7020976Smckusick  *
7120976Smckusick  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
7220976Smckusick  */
7320976Smckusick #define	DHU_DEF_TIMO	20
7420976Smckusick 
7520976Smckusick /*
7620976Smckusick  * Other values for silo timeout register defined here but not used:
7720976Smckusick  * receive interrupt only on modem control or silo alarm (3/4 full)
7820976Smckusick  */
7920976Smckusick #define DHU_POLL_TIMO	0
8020976Smckusick /*
8120976Smckusick  * receive interrupt immediately on receive character
8220976Smckusick  */
8320976Smckusick #define DHU_NO_TIMO	1
8420976Smckusick 
8520976Smckusick /*
8620976Smckusick  * Local variables for the driver
8720976Smckusick  */
8820976Smckusick /*
8920976Smckusick  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
9020976Smckusick  *	EXTA => 19200 baud
9120976Smckusick  *	EXTB => 2000 baud
9220976Smckusick  */
9337606Smarc struct speedtab dhuspeedtab[] = {
9437606Smarc 	19200,	14,
9537606Smarc 	9600,	13,
9637606Smarc 	4800,	11,
9737606Smarc 	2400,	10,
9837606Smarc 	2000,	9,
9937606Smarc 	1800,	8,
10037606Smarc 	1200,	7,
10137606Smarc 	600,	6,
10237606Smarc 	300,	5,
10337606Smarc 	150,	4,
10437606Smarc 	134,	3,
10537606Smarc 	110,	2,
10637606Smarc 	75,	1,
10737606Smarc 	0,	0,
10839061Smarc 	EXTA,	14,
10939061Smarc 	EXTB,	9,
11037606Smarc 	-1,	-1,
11137606Smarc };
11220976Smckusick 
11320976Smckusick short	dhusoftCAR[NDHU];
11420976Smckusick 
11520976Smckusick struct	tty dhu_tty[NDHULINE];
11620976Smckusick int	ndhu = NDHULINE;
11720976Smckusick int	dhuact;				/* mask of active dhu's */
11820976Smckusick int	dhustart(), ttrstrt();
11920976Smckusick 
12020976Smckusick /*
12130322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
12230322Skarels  * The identity of the board which allocated resources is recorded,
12330322Skarels  * so the process may be repeated after UNIBUS resets.
12420976Smckusick  * The UBACVT macro converts a clist space address for unibus uban
12520976Smckusick  * into an i/o space address for the DMA routine.
12620976Smckusick  */
12730322Skarels int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
12830322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
12920976Smckusick #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
13020976Smckusick 
13120976Smckusick /*
13220976Smckusick  * Routine for configuration to force a dhu to interrupt.
13320976Smckusick  */
13420976Smckusick /*ARGSUSED*/
dhuprobe(reg)13520976Smckusick dhuprobe(reg)
13620976Smckusick 	caddr_t reg;
13720976Smckusick {
13820976Smckusick 	register int br, cvec;		/* these are ``value-result'' */
13920976Smckusick 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
14020976Smckusick 	int i;
14120976Smckusick 
14220976Smckusick #ifdef lint
14320976Smckusick 	br = 0; cvec = br; br = cvec;
14420976Smckusick 	if (ndhu == 0) ndhu = 1;
14520976Smckusick 	dhurint(0); dhuxint(0);
14620976Smckusick #endif
14720976Smckusick 	/*
14820976Smckusick 	 * The basic idea here is:
14920976Smckusick 	 *	do a self-test by setting the Master-Reset bit
15020976Smckusick 	 *	if this fails, then return
15120976Smckusick 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
15220976Smckusick 	 *	therefore ask for a  Received-Data-Available interrupt
15320976Smckusick 	 *	wait for it...
15420976Smckusick 	 *	reset the interrupt-enable bit and flush out the diag. codes
15520976Smckusick 	 */
15620976Smckusick 	dhuaddr->dhucsr = DHU_CS_MCLR;
15720976Smckusick 	for (i = 0; i < 1000; i++) {
15820976Smckusick 		DELAY(10000);
15920976Smckusick 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
16020976Smckusick 			break;
16120976Smckusick 	}
16220976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
16320976Smckusick 		return(0);
16420976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
16520976Smckusick 		return(0);
16620976Smckusick 	dhuaddr->dhucsr = DHU_CS_RIE;
16720976Smckusick 	DELAY(1000);
16820976Smckusick 	dhuaddr->dhucsr = 0;
16920976Smckusick 	while (dhuaddr->dhurbuf < 0)
17020976Smckusick 		/* void */;
17120976Smckusick 	return (sizeof(struct dhudevice));
17220976Smckusick }
17320976Smckusick 
17420976Smckusick /*
17520976Smckusick  * Routine called to attach a dhu.
17620976Smckusick  */
17720976Smckusick dhuattach(ui)
17820976Smckusick 	struct uba_device *ui;
17920976Smckusick {
18020976Smckusick 
18120976Smckusick 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
18226220Skarels 	cbase[ui->ui_ubanum] = -1;
18336610Sbostic 	dhu_uballoc[ui->ui_ubanum] = -1;
18420976Smckusick }
18520976Smckusick 
18620976Smckusick /*
18720976Smckusick  * Open a DHU11 line, mapping the clist onto the uba if this
18820976Smckusick  * is the first dhu on this uba.  Turn on this dhu if this is
18920976Smckusick  * the first use of it.
19020976Smckusick  */
19120976Smckusick /*ARGSUSED*/
dhuopen(dev,flag)19220976Smckusick dhuopen(dev, flag)
19320976Smckusick 	dev_t dev;
19420976Smckusick {
19520976Smckusick 	register struct tty *tp;
19620976Smckusick 	register int unit, dhu;
19720976Smckusick 	register struct dhudevice *addr;
19820976Smckusick 	register struct uba_device *ui;
19940729Skarels 	int s, error = 0;
20037606Smarc 	extern dhuparam();
20120976Smckusick 
20220976Smckusick 	unit = UNIT(dev);
20320976Smckusick 	dhu = unit >> 4;
20420976Smckusick 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
20520976Smckusick 		return (ENXIO);
20620976Smckusick 	tp = &dhu_tty[unit];
20720976Smckusick 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
20820976Smckusick 		return (EBUSY);
20920976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
21020976Smckusick 	tp->t_addr = (caddr_t)addr;
21120976Smckusick 	tp->t_oproc = dhustart;
21237606Smarc 	tp->t_param = dhuparam;
21320976Smckusick 	/*
21420976Smckusick 	 * While setting up state for this uba and this dhu,
21520976Smckusick 	 * block uba resets which can clear the state.
21620976Smckusick 	 */
21720976Smckusick 	s = spl5();
21826220Skarels 	if (cbase[ui->ui_ubanum] == -1) {
21930322Skarels 		dhu_uballoc[ui->ui_ubanum] = dhu;
22030322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
22130322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
22220976Smckusick 	}
22320976Smckusick 	if ((dhuact&(1<<dhu)) == 0) {
22420976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
22520976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
22620976Smckusick 		dhuact |= (1<<dhu);
22720976Smckusick 		/* anything else to configure whole board */
22820976Smckusick 	}
22920976Smckusick 	(void) splx(s);
23020976Smckusick 	/*
23120976Smckusick 	 * If this is first open, initialize tty state to default.
23220976Smckusick 	 */
23320976Smckusick 	if ((tp->t_state&TS_ISOPEN) == 0) {
23444393Smarc 		tp->t_state |= TS_WOPEN;
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;
26140729Skarels 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
26240729Skarels 	    (tp->t_state & TS_CARR_ON) == 0) {
26320976Smckusick 		tp->t_state |= TS_WOPEN;
26444393Smarc 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
26544393Smarc 		    ttopen, 0))
26640729Skarels 			break;
26720976Smckusick 	}
26820976Smckusick 	(void) splx(s);
26940729Skarels 	if (error)
27040729Skarels 		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*/
dhuclose(dev,flag,mode,p)278*49759Smarc dhuclose(dev, flag, mode, p)
27920976Smckusick 	dev_t dev;
280*49759Smarc 	int flag, mode;
281*49759Smarc 	struct proc *p;
28220976Smckusick {
28320976Smckusick 	register struct tty *tp;
28420976Smckusick 	register unit;
28520976Smckusick 
28620976Smckusick 	unit = UNIT(dev);
28720976Smckusick 	tp = &dhu_tty[unit];
288*49759Smarc 	(*linesw[tp->t_line].l_close)(tp, flag);
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 
dhuread(dev,uio,flag)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 
dhuwrite(dev,uio,flag)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  */
dhurint(dhu)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*/
dhuioctl(dev,cmd,data,flag)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 
dmtodhu(bits)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 
dhutodm(bits)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  */
dhuparam(tp,want)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);
49746352Skarels 		return (0);
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);
54646352Skarels 	return (0);
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  */
dhuxint(dhu)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  */
dhustart(tp)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;
64339061Smarc 	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*/
dhustop(tp,flag)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  */
dhumctl(dev,bits,how)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  */
dhureset(uban)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