xref: /csrg-svn/sys/vax/uba/dmz.c (revision 26837)
125224Smckusick /*
225224Smckusick  * Copyright (c) 1985 Regents of the University of California.
325224Smckusick  * All rights reserved.  The Berkeley software License Agreement
425224Smckusick  * specifies the terms and conditions for redistribution.
525224Smckusick  *
6*26837Skarels  *	@(#)dmz.c	6.6 (Berkeley) 03/13/86
725224Smckusick  */
825224Smckusick 
925224Smckusick /*
1025224Smckusick  * DMZ-32 driver
1125224Smckusick  * HISTORY
1225224Smckusick  * 23-Apr-85  Joe Camaratta (jcc) at Siemens RTL
1325224Smckusick  *	Driver for DEC's DMZ32 24-line asynchronous multiplexor.
1425224Smckusick  *	Based on Chris Maloney's driver for DEC's DMF32
1525224Smckusick  *
1625224Smckusick  * 9-Aug-85	Mike Meyer (mwm) at ucb
1725224Smckusick  *	Mangled into shape for 4.3.
1825224Smckusick  */
1925224Smckusick 
2025224Smckusick #include "dmz.h"
2125224Smckusick #if NDMZ > 0
2225224Smckusick 
2325224Smckusick 
2425224Smckusick #include "../machine/pte.h"
2525224Smckusick 
2625224Smckusick 
2725224Smckusick #include "bk.h"
2825224Smckusick #include "uba.h"
2925224Smckusick #include "param.h"
3025224Smckusick #include "conf.h"
3125224Smckusick #include "dir.h"
3225224Smckusick #include "user.h"
33*26837Skarels #include "proc.h"
3425224Smckusick #include "ioctl.h"
3525224Smckusick #include "tty.h"
3625224Smckusick #include "map.h"
3725224Smckusick #include "buf.h"
3825224Smckusick #include "vm.h"
3925224Smckusick #include "bkmac.h"
4025224Smckusick #include "clist.h"
4125224Smckusick #include "file.h"
4225224Smckusick #include "uio.h"
4325224Smckusick #include "kernel.h"
4425435Skarels #include "syslog.h"
4525224Smckusick 
4625224Smckusick #include "ubareg.h"
4725224Smckusick #include "ubavar.h"
4825224Smckusick #include "dmzreg.h"
4925655Skarels #include "dmreg.h"
5025224Smckusick 
5125224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint();
5225224Smckusick struct uba_device *dmzinfo[NDMZ];
5325224Smckusick u_short dmzstd[] = {0, 0};
5425224Smckusick struct uba_driver dmzdriver = {
5525224Smckusick 	dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo
5625224Smckusick };
5725224Smckusick 
5825224Smckusick #define	NDMZLINES	(NDMZ*24)
5925224Smckusick 
6025224Smckusick int ttrstrt();
6125224Smckusick struct tty dmz_tty[NDMZLINES];
6225224Smckusick 
6325224Smckusick int dmzsoftCAR[NDMZ];
6425224Smckusick 
6525224Smckusick struct {
6625224Smckusick 	char dmz_state;		/* dmz state */
6725224Smckusick 	int dmz_count;		/* dmz dma count */
6825224Smckusick } dmz_softc[NDMZ*24];
6925224Smckusick 
7025224Smckusick #define	ST_TXOFF	(0x01)	/* transmission turned off (^S) */
7125224Smckusick #define	ST_DMA		(0x02)	/* dma inprogress */
7225224Smckusick #define	ST_INBUSY	(0x04)	/* stop transmission in busy */
7325224Smckusick 
7425224Smckusick char dmz_speeds[] = {
7525224Smckusick 	0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0
7625224Smckusick };
7725224Smckusick 
7825396Skarels #ifndef	PORTSELECTOR
7925396Skarels #define	ISPEED	B9600
8025396Skarels #define	IFLAGS	(EVENP|ODDP|ECHO)
8125396Skarels #else
8225396Skarels #define	ISPEED	B4800
8325396Skarels #define	IFLAGS	(EVENP|ODDP)
8425396Skarels #endif
8525396Skarels 
8625224Smckusick #ifndef lint
8725224Smckusick int ndmz = NDMZLINES;		/* Used by pstat/iostat */
8825224Smckusick #endif
8925224Smckusick 
9025224Smckusick short dmzact[NDMZ];		/* Mask of active octets on the dmz */
9125224Smckusick int dmzstart();
9225224Smckusick 
9325224Smckusick /*
9425224Smckusick  * SILO_TIMEOUT represents the number of milliseconds characters can sit
9525224Smckusick  * in the input silo without causing an interrupt.  If data overruns or
9625224Smckusick  * slow XON/XOFF occur, set it lower but AT LEAST equal to 1.
9725224Smckusick  */
9825224Smckusick #define	SILO_TIMEOUT	(3)
9925224Smckusick 
10025224Smckusick /*
10125224Smckusick  * DO_DMA_COUNT represents the threshold of the number of output
10225224Smckusick  * characters beyond which the driver uses DMA mode.
10325224Smckusick  */
10425224Smckusick #define	DO_DMA_COUNT	(10)
10525224Smckusick 
10625224Smckusick #define	TRUE		(1)
10725224Smckusick #define	FALSE		(0)
10825224Smckusick 
10925435Skarels int cbase[NUBA];		/* base address in unibus map */
11025224Smckusick int dmz_ubinfo[NUBA];		/* info about allocated unibus map */
11125224Smckusick 
11225224Smckusick #define	UBACVT(x, uban)	    (cbase[uban] + ((x) - (char *)cfree))
11325224Smckusick 
11425224Smckusick /* These flags are for debugging purposes only */
11525224Smckusick int dmz_dma_on = 1;
11625224Smckusick 
11725224Smckusick dmzprobe(reg)
11825224Smckusick 	caddr_t reg;
11925224Smckusick {
12025224Smckusick 	register int br, cvec;
12125224Smckusick 	register struct dmzdevice *dmz_addr;
12225224Smckusick 	register unsigned int a;
12325224Smckusick 
12425224Smckusick 	dmz_addr = (struct dmzdevice *)reg;
12525224Smckusick 
12625224Smckusick #ifdef lint
12725224Smckusick 	br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0);
12825224Smckusick 	dmzrinta(0); dmzrintb(0); dmzrintc(0);
12925224Smckusick #endif
13025224Smckusick 
13125224Smckusick 	br = 0x15;
13225224Smckusick 
13325224Smckusick 	a = dmz_addr->dmz_config;
13425224Smckusick 	if (((a>>12) & ~DMZ_INTERFACE) != 0) {
13525224Smckusick 		printf("	Unknown interface type\n");
13625224Smckusick 		return (0);
13725224Smckusick 	}
13825224Smckusick 	if (((a>>8) & DMZ_NOC_MASK) != 3) {
13925224Smckusick 		printf("	Not all octets are available\n");
14025224Smckusick 		return (0);
14125224Smckusick 	}
14225224Smckusick 
14325224Smckusick 	cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6);
14425224Smckusick 	dmz_addr->dmz_config = cvec >> 2;
14525224Smckusick 
14625224Smckusick 	return (sizeof(struct dmzdevice));
14725224Smckusick }
14825224Smckusick 
14925224Smckusick dmzattach(ui)
15025224Smckusick 	struct uba_device *ui;
15125224Smckusick {
15225224Smckusick 	dmzsoftCAR[ui->ui_unit] = ui->ui_flags;
15326218Skarels 	cbase[ui->ui_ubanum] = -1;
15425224Smckusick }
15525224Smckusick 
15625224Smckusick /* ARGSUSED */
15725224Smckusick dmzopen(device, flag)
15825224Smckusick 	dev_t device;
15925224Smckusick 	int flag;
16025224Smckusick {
16125224Smckusick 	register struct tty *tp;
16225224Smckusick 	register int unit, controller;
16325224Smckusick 	register struct dmzdevice *dmz_addr;
16425224Smckusick 	register struct uba_device *ui;
16525224Smckusick 	int priority;
16625224Smckusick 	int octet;
16725224Smckusick 
16825224Smckusick 	unit = minor(device);
16925224Smckusick 	controller = DMZ(unit);
17025224Smckusick 	octet = OCTET(unit);
17125224Smckusick 
17225224Smckusick 	if (unit >= NDMZLINES ||
17325224Smckusick 	    (ui = dmzinfo[controller]) == 0 ||
17425224Smckusick 	    ui->ui_alive == 0)
17525224Smckusick 		return (ENXIO);
17625224Smckusick 
17725224Smckusick 	tp = &dmz_tty[unit];
17825224Smckusick 
17925224Smckusick 	if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0)
18025224Smckusick 		return (EBUSY);
18125224Smckusick 
18225224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
18325224Smckusick 	tp->t_addr = (caddr_t)dmz_addr;
18425224Smckusick 	tp->t_oproc = dmzstart;
18525224Smckusick 
18625224Smckusick 	/*
18725224Smckusick 	 * Set up Unibus map registers.  Block uba resets, which can
18825224Smckusick 	 * clear the state.
18925224Smckusick 	 */
19025224Smckusick 	priority = spl5();
19126218Skarels 	if (cbase[ui->ui_ubanum] == -1) {
19225224Smckusick 		dmz_ubinfo[ui->ui_ubanum] =
19325224Smckusick 			uballoc(ui->ui_ubanum, (caddr_t)cfree,
19425224Smckusick 				nclist * sizeof(struct cblock), 0);
19525224Smckusick 		if (dmz_ubinfo[ui->ui_ubanum] == 0) {
19625224Smckusick 			splx(priority);
19725224Smckusick 			printf("dmz: insufficient unibus map regs\n");
19825435Skarels 			return (ENOMEM);
19925224Smckusick 		}
20026218Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(dmz_ubinfo[ui->ui_ubanum]);
20125224Smckusick 	}
20225224Smckusick 
20325224Smckusick 	if ((dmzact[controller] & (1 << octet)) == 0) {
20425224Smckusick 		dmz_addr->octet[octet].octet_csr |= DMZ_IE;
20525224Smckusick 		dmzact[controller] |= 1 << octet;
20625224Smckusick 		dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
20725224Smckusick 	}
20825224Smckusick 
20925224Smckusick 	splx(priority);
21025224Smckusick 
21125224Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
21225224Smckusick 		ttychars(tp);
21325396Skarels 		tp->t_ispeed = tp->t_ospeed = ISPEED;
21425396Skarels 		tp->t_flags = IFLAGS;
21525224Smckusick 		dmz_softc[unit].dmz_state = 0;
21625224Smckusick 	}
21725655Skarels 	dmzparam(unit);
21825224Smckusick 
21925224Smckusick 	/*
22025224Smckusick 	 * Wait for carrier, then process line discipline specific open.
22125224Smckusick 	 */
22225655Skarels 	if ((dmzmctl(unit, DMZ_ON, DMSET) & DMZ_CAR) ||
22325224Smckusick 	    (dmzsoftCAR[controller] & (1 << (unit % 24))))
22425224Smckusick 		tp->t_state |= TS_CARR_ON;
22525224Smckusick 	priority = spl5();
22625224Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
22725224Smckusick 		tp->t_state |= TS_WOPEN;
22825224Smckusick 		sleep((caddr_t) &tp->t_rawq, TTIPRI);
22925224Smckusick 	}
23025224Smckusick 	splx(priority);
23125224Smckusick 
23225435Skarels 	return ((*linesw[tp->t_line].l_open)(device, tp));
23325224Smckusick }
23425224Smckusick 
23525224Smckusick dmzparam(unit)
23625224Smckusick 	register int unit;
23725224Smckusick {
23825224Smckusick 	register struct tty *tp;
23925224Smckusick 	register struct dmzdevice *dmz_addr;
24025655Skarels 	register int line_parameters;
24125224Smckusick 	register int octet;
24225224Smckusick 	int priority;
24325224Smckusick 
24425224Smckusick 	octet = OCTET(unit);
24525224Smckusick 
24625224Smckusick 	tp = &dmz_tty[unit];
24725224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
24825224Smckusick 
24925224Smckusick 	priority = spl5();
25025224Smckusick 	if ((tp->t_ispeed) == 0) {
25125224Smckusick 		tp->t_state |= TS_HUPCLS;
25225224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
25325224Smckusick 		splx(priority);
25425224Smckusick 		return;
25525224Smckusick 	}
25625224Smckusick 
25725224Smckusick 	line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8);
25825224Smckusick 
25925224Smckusick 	if ((tp->t_ispeed) == B134)
26025224Smckusick 		line_parameters |= DMZ_6BT | DMZ_PEN;
26125655Skarels 	else if (tp->t_flags & (RAW | LITOUT | PASS8))
26225224Smckusick 		line_parameters |= DMZ_8BT;
26325224Smckusick 	else
26425224Smckusick 		line_parameters |= DMZ_7BT | DMZ_PEN;
26525224Smckusick 
26625224Smckusick 	if (tp->t_flags & EVENP)
26725224Smckusick 		line_parameters |= DMZ_EPR;
26825224Smckusick 	if ((tp->t_ospeed) == B110)
26925224Smckusick 		line_parameters |= DMZ_SCD;
27025224Smckusick 
27125224Smckusick 	line_parameters |= (unit & 07);
27225224Smckusick 
27325224Smckusick 	dmz_addr->octet[octet].octet_lprm = line_parameters;
27425224Smckusick 	splx(priority);
27525224Smckusick }
27625224Smckusick 
27725224Smckusick /* ARGSUSED */
27825224Smckusick dmzclose(device, flag)
27925224Smckusick 	dev_t device;
28025224Smckusick 	int flag;
28125224Smckusick {
28225224Smckusick 	register struct  tty *tp;
28325224Smckusick 	register int unit;
28425224Smckusick 
28525224Smckusick 	unit = minor(device);
28625224Smckusick 	tp = &dmz_tty[unit];
28725655Skarels 	(*linesw[tp->t_line].l_close)(tp);
28825224Smckusick 
28925224Smckusick 	/*
29025655Skarels 	 * Clear break, hang-up and close the modem.
29125224Smckusick 	 */
29225224Smckusick 	(void) dmzmctl(unit, DMZ_BRK, DMBIC);
29325224Smckusick 	if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
29425224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
29525224Smckusick 	ttyclose(tp);
29625224Smckusick 	return;
29725224Smckusick }
29825224Smckusick 
29925224Smckusick dmzreset(uban)
30025224Smckusick 	int uban;
30125224Smckusick {
30225224Smckusick 	register int controller, unit;
30325224Smckusick 	register struct tty *tp;
30425224Smckusick 	register struct uba_device *ui;
30525224Smckusick 	register struct dmzdevice *dmz_addr;
30625224Smckusick 	int i;
30725224Smckusick 	int octet;
30825224Smckusick 
30925224Smckusick 	for (controller = 0; controller < NDMZ; controller++) {
31025224Smckusick 		ui = dmzinfo[controller];
31125224Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
31225224Smckusick 			continue;
31325224Smckusick 		printf("dmz%d ", controller);
31425224Smckusick 		dmz_addr = (struct dmzdevice *) ui->ui_addr;
31525224Smckusick 
31626218Skarels 		if (dmz_ubinfo[uban]) {
31725435Skarels 			dmz_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
31825435Skarels 				nclist * sizeof(struct cblock), 0);
31926218Skarels 			cbase[uban] = UBAI_ADDR(dmz_ubinfo[uban]);
32025435Skarels 		}
32125435Skarels 
32225224Smckusick 		for (octet = 0; octet < 3; octet++)
32325224Smckusick 			if ((dmzact[controller] & (1 << octet)) != 0) {
32425224Smckusick 				dmz_addr->octet[octet].octet_csr |= DMZ_IE;
32525224Smckusick 				dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
32625224Smckusick 			}
32725224Smckusick 
32825224Smckusick 		unit = controller * 24;
32925224Smckusick 
33025224Smckusick 		/*
33125224Smckusick 		 * If a unit is open or waiting for open to complete,
33225224Smckusick 		 * reset it.
33325224Smckusick 		 */
33425224Smckusick 		for (i = 0; i < 24; i++) {
33525224Smckusick 			dmz_softc[unit].dmz_state = 0;
33625224Smckusick 			tp = &dmz_tty[unit];
33725224Smckusick 			if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) {
33825224Smckusick 				dmzparam(unit);
33925224Smckusick 				(void) dmzmctl(unit, DMZ_ON, DMSET);
34025224Smckusick 				tp->t_state &= ~TS_BUSY;
34125224Smckusick 				dmzstart(tp);
34225224Smckusick 			}
34325224Smckusick 			unit++;
34425224Smckusick 		}
34525224Smckusick 	}
34625224Smckusick 	return;
34725224Smckusick }
34825224Smckusick 
34925224Smckusick dmzread(device, uio)
35025224Smckusick 	dev_t device;
35125224Smckusick 	struct uio *uio;
35225224Smckusick {
35325224Smckusick 	register struct tty *tp;
35425224Smckusick 	int xstatus;
35525224Smckusick 
35625224Smckusick 	tp = &dmz_tty[minor(device)];
35725224Smckusick 	xstatus = (*linesw[tp->t_line].l_read)(tp, uio);
35825224Smckusick 	return (xstatus);
35925224Smckusick }
36025224Smckusick 
36125224Smckusick dmzwrite(device, uio)
36225224Smckusick 	dev_t device;
36325224Smckusick 	struct uio *uio;
36425224Smckusick {
36525224Smckusick 	register struct tty *tp;
36625224Smckusick 	int xstatus;
36725224Smckusick 
36825224Smckusick 	tp = &dmz_tty[minor(device)];
36925224Smckusick 	xstatus = (*linesw[tp->t_line].l_write)(tp, uio);
37025224Smckusick 	return (xstatus);
37125224Smckusick }
37225224Smckusick 
37325224Smckusick dmzrinta(controller)
37425224Smckusick 	int controller;
37525224Smckusick {
37625224Smckusick 	dmzrint(controller, 0);
37725224Smckusick }
37825224Smckusick 
37925224Smckusick dmzrintb(controller)
38025224Smckusick 	int controller;
38125224Smckusick {
38225224Smckusick 	dmzrint(controller, 1);
38325224Smckusick }
38425224Smckusick 
38525224Smckusick dmzrintc(controller)
38625224Smckusick 	int controller;
38725224Smckusick {
38825224Smckusick 	dmzrint(controller, 2);
38925224Smckusick }
39025224Smckusick 
39125224Smckusick dmzrint(controller, octet)
39225224Smckusick 	int controller;
39325224Smckusick 	register int octet;
39425224Smckusick {
39525224Smckusick 	register struct tty *tp;
39625224Smckusick 	register int character;
39725224Smckusick 	register struct dmzdevice *dmz_addr;
39825224Smckusick 	register struct tty *tp0;
39925224Smckusick 	register int unit;
40025224Smckusick 	register struct uba_device *ui;
40125396Skarels 	int overrun;
40225224Smckusick 
40325224Smckusick 	overrun = 0;
40425224Smckusick 	ui = dmzinfo[controller];
40525224Smckusick 	if (ui == 0 || ui->ui_alive == 0)
40625224Smckusick 		return;
40725224Smckusick 	dmz_addr = (struct dmzdevice *) ui->ui_addr;
40825224Smckusick 	tp0 = &dmz_tty[controller * 24];
40925224Smckusick 
41025224Smckusick 	while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) {
41125224Smckusick 		unit = (character >> 8) & 07;	/* unit is bits 8-10 of rb */
41225224Smckusick 		tp = tp0 + (octet * 8 + unit);
41325224Smckusick 
41426218Skarels 		if (character & DMZ_DSC) {
41525655Skarels 			dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | unit;
41625655Skarels 			if (dmz_addr->octet[octet].octet_rmstsc & DMZ_CAR)
41725396Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
41826218Skarels 			else if (dmzsoftCAR[controller] &
41926218Skarels 			  (1 << (octet * 8 + unit)) == 0 &&
42026218Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
42125655Skarels 				(void)dmzmctl(tp - dmz_tty, DMZ_OFF, DMSET);
42225224Smckusick 			continue;
42325224Smckusick 		}
42425224Smckusick 
42525396Skarels 		if ((tp->t_state&TS_ISOPEN)==0) {
42625396Skarels 			wakeup((caddr_t)&tp->t_rawq);
42725396Skarels #ifdef PORTSELECTOR
42825396Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
42925396Skarels #endif
43025396Skarels 				continue;
43125224Smckusick 		}
43225224Smckusick 
43325224Smckusick 		if (character & DMZ_PE) {
43425224Smckusick 			if ((tp->t_flags & (EVENP | ODDP)) == EVENP ||
43525224Smckusick 			    (tp->t_flags & (EVENP | ODDP)) == ODDP)
43625224Smckusick 				continue;
43725224Smckusick 		}
43825224Smckusick 
43925224Smckusick 		if ((character & DMZ_DO) && overrun == 0) {
44025435Skarels 			log(LOG_WARNING, "dmz%d: silo overflow\n", controller);
44125224Smckusick 			overrun = 1;
44225224Smckusick 		}
44325224Smckusick 
44425224Smckusick 		if (character & DMZ_FE) {
44525224Smckusick 			if (tp->t_flags & RAW)
44625224Smckusick 				character = 0;
44725224Smckusick 			else
44825224Smckusick 				character = tp->t_intrc;
44925224Smckusick 		}
45025224Smckusick 
45125224Smckusick 		(*linesw[tp->t_line].l_rint)(character, tp);
45225224Smckusick 	}
45325224Smckusick 
45425224Smckusick 	return;
45525224Smckusick }
45625224Smckusick 
45725224Smckusick dmzxinta(controller)
45825224Smckusick 	int controller;
45925224Smckusick {
46025224Smckusick 	dmzxint(controller, 0);
46125224Smckusick }
46225224Smckusick 
46325224Smckusick dmzxintb(controller)
46425224Smckusick 	int controller;
46525224Smckusick {
46625224Smckusick 	dmzxint(controller, 1);
46725224Smckusick }
46825224Smckusick 
46925224Smckusick dmzxintc(controller)
47025224Smckusick 	int controller;
47125224Smckusick {
47225224Smckusick 	dmzxint(controller, 2);
47325224Smckusick }
47425224Smckusick 
47525224Smckusick dmzxint(controller, octet)
47625224Smckusick 	int controller;
47725224Smckusick 	register int octet;
47825224Smckusick {
47925224Smckusick 	register struct tty *tp;
48025224Smckusick 	register struct dmzdevice *dmz_addr;
48125224Smckusick 	register struct uba_device *ui;
48225224Smckusick 	register int unit, t;
48325224Smckusick 	int priority;
48425224Smckusick 
48525224Smckusick 	ui = dmzinfo[controller];
48625224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
48725224Smckusick 
48825224Smckusick 	priority = spl5();
48925224Smckusick 
49025224Smckusick 	while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) {
49125224Smckusick 		unit = controller * 24 + (octet * 8 + ((t>>8) & 07));
49225224Smckusick 		tp = &dmz_tty[unit];
49325224Smckusick 		tp->t_state &= ~TS_BUSY;
49425224Smckusick 
49525224Smckusick 		if (t & DMZ_NXM)
49625224Smckusick 			printf("dmz%d: NXM line %d\n", controller,
49725224Smckusick 				octet * 8 + (unit & 07));
49825224Smckusick 
49925224Smckusick 		if (tp->t_state & TS_FLUSH) {
50025224Smckusick 			tp->t_state &= ~TS_FLUSH;
50125224Smckusick 			dmz_addr->octet[octet].octet_csr =
50225224Smckusick 				DMZ_IE | IR_LCTMR | (unit & 07);
50325224Smckusick 			dmz_addr->octet[octet].octet_lctmr =
50425224Smckusick 				(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
50525224Smckusick 		} else
50625224Smckusick 			if (dmz_softc[unit].dmz_state & ST_DMA)
50725224Smckusick 				ndflush(&tp->t_outq, dmz_softc[unit].dmz_count);
50825224Smckusick 		dmz_softc[unit].dmz_state = 0;
50925224Smckusick 
51025224Smckusick 		if (tp->t_line)
51125224Smckusick 			(*linesw[tp->t_line].l_start)(tp);
51225224Smckusick 		else
51325224Smckusick 			dmzstart(tp);
51425224Smckusick 	}
51525224Smckusick 
51625224Smckusick 	splx(priority);
51725224Smckusick 	return;
51825224Smckusick }
51925224Smckusick 
52025224Smckusick dmzstart(tp)
52125224Smckusick 	register struct tty *tp;
52225224Smckusick {
52325224Smckusick 	register struct dmzdevice *dmz_addr;
52425224Smckusick 	register int unit, nch, room;
52525224Smckusick 	int controller, octet;
52625224Smckusick 	int priority, car, use_dma;
52725224Smckusick 	register int i;
52825224Smckusick 	register char *cp;
52925224Smckusick 
53025224Smckusick 	unit = minor(tp->t_dev);
53125224Smckusick 	controller = DMZ(unit);
53225224Smckusick 	octet = OCTET(unit);
53325224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
53425224Smckusick 
53525224Smckusick 	priority = spl5();
53625224Smckusick 
53725224Smckusick 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
53825224Smckusick 		goto out;
53925224Smckusick 
54025224Smckusick 	/*
54125224Smckusick 	 * If the transmitter has been disabled, reenable it.
54225224Smckusick 	 * If the transmitter was disabled before the xint (the
54325224Smckusick 	 * ST_INBUSY was still on), then reset the BUSY state and
54425224Smckusick 	 * we will wait for the interrupt.  If !TS_BUSY, we already
54525224Smckusick 	 * saw the interrupt so we can start another transmission.
54625224Smckusick 	 */
54725224Smckusick 	if (dmz_softc[unit].dmz_state & ST_TXOFF) {
54825224Smckusick 		dmz_addr->octet[octet].octet_csr =
54925224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
55025224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
55125224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
55225224Smckusick 		dmz_softc[unit].dmz_state &= ~ST_TXOFF;
55325224Smckusick 		if (dmz_softc[unit].dmz_state & ST_INBUSY) {
55425224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_INBUSY;
55525224Smckusick 			tp->t_state |= TS_BUSY;
55625224Smckusick 			goto out;
55725224Smckusick 		}
55825224Smckusick 	}
55925224Smckusick 
56025224Smckusick 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
56125224Smckusick 		if (tp->t_state & TS_ASLEEP) {
56225224Smckusick 			tp->t_state &= ~TS_ASLEEP;
56325224Smckusick 			wakeup((caddr_t)&tp->t_outq);
56425224Smckusick 		}
56525224Smckusick 		if (tp->t_wsel) {
56625224Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
56725224Smckusick 			tp->t_wsel = 0;
56825224Smckusick 			tp->t_state &= ~TS_WCOLL;
56925224Smckusick 		}
57025224Smckusick 	}
57125224Smckusick 
57225224Smckusick 	if (tp->t_outq.c_cc == 0)
57325224Smckusick 		goto out;
57425655Skarels 	if (tp->t_flags & (RAW | LITOUT | PASS8))
57525224Smckusick 		nch = ndqb(&tp->t_outq, 0);
57625224Smckusick 	else {
57725224Smckusick 		nch = ndqb(&tp->t_outq, 0200);
57825224Smckusick 		if (nch == 0) {
57925224Smckusick 			nch = getc(&tp->t_outq);
58025224Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6);
58125224Smckusick 			tp->t_state |= TS_TIMEOUT;
58225224Smckusick 			goto out;
58325224Smckusick 		}
58425224Smckusick 	}
58525224Smckusick 
58625224Smckusick 	/*
58725224Smckusick 	 * Should we use DMA or SILO mode?
58825224Smckusick 	 * If nch is greater than DO_DMA_COUNT then DMA.
58925224Smckusick 	 */
59025224Smckusick 	if (nch) {
59125224Smckusick 		dmz_addr->octet[octet].octet_csr =
59225224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
59325224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
59425224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
59525224Smckusick 		tp->t_state |= TS_BUSY;
59625224Smckusick 
59725224Smckusick 		use_dma = FALSE;
59825224Smckusick 		room = DMZ_SIZ;
59925224Smckusick 
60025224Smckusick 		if (nch > DO_DMA_COUNT)
60125224Smckusick 			use_dma = TRUE;
60225224Smckusick 
60325224Smckusick 		if (use_dma && dmz_dma_on) {
60425224Smckusick 			car = UBACVT(tp->t_outq.c_cf,
60525224Smckusick 				dmzinfo[controller]->ui_ubanum);
60625224Smckusick 			dmz_softc[unit].dmz_count = nch;
60725224Smckusick 			dmz_softc[unit].dmz_state |= ST_DMA;
60825224Smckusick 			dmz_addr->octet[octet].octet_csr =
60925224Smckusick 				DMZ_IE | IR_TBA | (unit & 07);
61025224Smckusick 			dmz_addr->octet[octet].octet_tba = car;
61125224Smckusick 			dmz_addr->octet[octet].octet_tcc =
61225224Smckusick 				((car >> 2) & 0xc000) | nch;
61325224Smckusick 		} else {
61425224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_DMA;
61525224Smckusick 			cp = tp->t_outq.c_cf;
61625224Smckusick 			nch = MIN(nch, room);
61725224Smckusick 			dmz_addr->octet[octet].octet_csr =
61825224Smckusick 				DMZ_IE | IR_TBUF | (unit & 07);
61925224Smckusick 			for (i = 0; i < nch; i++)
62025224Smckusick 				dmz_addr->octet[octet].octet_tbf = *cp++ ;
62125224Smckusick 			ndflush(&tp->t_outq, nch);
62225224Smckusick 		}
62325224Smckusick 	}
62425224Smckusick 
62525224Smckusick out:
62625224Smckusick 	splx(priority);
62725224Smckusick 	return;
62825224Smckusick }
62925224Smckusick 
63025224Smckusick /* ARGSUSED */
63125224Smckusick dmzstop(tp, flag)
63225224Smckusick 	register struct tty *tp;
63325224Smckusick {
63425224Smckusick 	register struct dmzdevice *dmz_addr;
63525224Smckusick 	register int unit, priority, octet;
63625224Smckusick 
63725224Smckusick 	priority = spl5();
63825224Smckusick 	dmz_addr = (struct dmzdevice *) tp->t_addr;
63925224Smckusick 	unit = minor(tp->t_dev);
64025224Smckusick 	octet = OCTET(unit);
64125224Smckusick 
64225224Smckusick 	dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE;
64325224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
64425224Smckusick 		(dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE);
64525224Smckusick 	dmz_softc[unit].dmz_state |= ST_TXOFF;
64625224Smckusick 	if ((tp->t_state & TS_TTSTOP) == 0) {
64725224Smckusick 		tp->t_state |= (TS_FLUSH | TS_BUSY);
64825224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
64925224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_FLS);
65025224Smckusick 	} else if (tp->t_state & TS_BUSY) {
65125224Smckusick 		dmz_softc[unit].dmz_state |= ST_INBUSY;
65225224Smckusick 		tp->t_state &= ~TS_BUSY;
65325224Smckusick 	}
65425224Smckusick 
65525224Smckusick 	splx(priority);
65625224Smckusick 	return;
65725224Smckusick }
65825224Smckusick 
65925224Smckusick /* ARGSUSED */
66025224Smckusick dmzioctl(device, command, data, flag)
66125224Smckusick 	dev_t device;
66225224Smckusick 	caddr_t data;
66325224Smckusick {
66425224Smckusick 	register struct tty *tp;
66525224Smckusick 	register int unit;
66625224Smckusick 	int error;
66725224Smckusick 
66825224Smckusick 	unit = minor(device);
66925224Smckusick 	tp = &dmz_tty[unit];
67025224Smckusick 
67125224Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag);
67225224Smckusick 	if (error >= 0)
67325224Smckusick 		return (error);
67425224Smckusick 	error = ttioctl(tp, command, data, flag);
67525224Smckusick 	if (error >= 0) {
67625655Skarels 		if (command == TIOCSETP || command == TIOCSETN ||
67725655Skarels 		    command == TIOCLSET || command == TIOCLBIS ||
67825655Skarels 		    command == TIOCLBIC)
67925224Smckusick 			dmzparam(unit);
68025224Smckusick 		return (error);
68125224Smckusick 	}
68225224Smckusick 
68325224Smckusick 	switch (command) {
68425224Smckusick 		case TIOCSBRK:
68525655Skarels 			(void) dmzmctl(unit, DMZ_BRK, DMBIS);
68625224Smckusick 			break;
68725224Smckusick 		case TIOCCBRK:
68825655Skarels 			(void) dmzmctl(unit, DMZ_BRK, DMBIC);
68925224Smckusick 			break;
69025224Smckusick 		case TIOCSDTR:
69125655Skarels 			(void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIS);
69225224Smckusick 			break;
69325224Smckusick 		case TIOCCDTR:
69425655Skarels 			(void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIC);
69525224Smckusick 			break;
69625224Smckusick 		case TIOCMSET:
69725655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMSET);
69825224Smckusick 			break;
69925224Smckusick 		case TIOCMBIS:
70025655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIS);
70125224Smckusick 			break;
70225224Smckusick 		case TIOCMBIC:
70325655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIC);
70425224Smckusick 			break;
70525224Smckusick 		case TIOCMGET:
70625655Skarels 			*(int *)data = dmzmctl(unit, 0, DMGET);
70725224Smckusick 			break;
70825224Smckusick 		default:
70925224Smckusick 			return (ENOTTY);
71025224Smckusick 	}
71125224Smckusick 	return (0);
71225224Smckusick }
71325224Smckusick 
71425655Skarels dmzmctl(unit, bits, how)
71525655Skarels 	register int unit;
71625224Smckusick 	int bits, how;
71725224Smckusick {
71825224Smckusick 	register struct dmzdevice *dmz_addr;
71925655Skarels 	register int modem_status, line_control;
72025224Smckusick 	int priority;
72125224Smckusick 	int octet;
72225224Smckusick 
72325224Smckusick 	octet = OCTET(unit);
72425655Skarels 	dmz_addr = (struct dmzdevice *) dmzinfo[DMZ(unit)]->ui_addr;
72525224Smckusick 
72625224Smckusick 	priority = spl5();
72725655Skarels 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | (unit & 07);
72825655Skarels 	modem_status = dmz_addr->octet[octet].octet_rmstsc & 0xff00;
72925224Smckusick 
73025224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
73125655Skarels 	line_control = dmz_addr->octet[octet].octet_lctmr;
73225224Smckusick 
73325224Smckusick 
73425224Smckusick 	switch (how) {
73525224Smckusick 		case DMSET:
73625655Skarels 			line_control = bits;
73725224Smckusick 			break;
73825224Smckusick 		case DMBIS:
73925655Skarels 			line_control |= bits;
74025224Smckusick 			break;
74125224Smckusick 		case DMBIC:
74225655Skarels 			line_control &= ~bits;
74325224Smckusick 			break;
74425224Smckusick 		case DMGET:
74525224Smckusick 			(void) splx(priority);
74625655Skarels 			return (dmztodm(modem_status, line_control));
74725224Smckusick 	}
74825224Smckusick 
74925224Smckusick 	dmz_addr->octet[octet].octet_csr =
75025224Smckusick 		DMZ_IE | IR_LCTMR | (unit & 07);
75125655Skarels 	dmz_addr->octet[octet].octet_lctmr = line_control;
75225224Smckusick 
75325655Skarels 	splx(priority);
75425224Smckusick 	return (modem_status);
75525224Smckusick }
75625224Smckusick 
75725224Smckusick /*
75825655Skarels  * Routine to convert modem status from dm to dmz lctmr format.
75925224Smckusick  */
76025224Smckusick dmtodmz(bits)
76125224Smckusick 	register int bits;
76225224Smckusick {
76325655Skarels 	register int lcr = DMZ_LCE;
76425224Smckusick 
76525655Skarels 	if (bits & DML_DTR)
76625655Skarels 		lcr |= DMZ_DTR;
76725655Skarels 	if (bits & DML_RTS)
76825655Skarels 		lcr |= DMZ_RTS;
76925655Skarels 	if (bits & DML_ST)
77025655Skarels 		lcr |= DMF_ST;
77125655Skarels 	if (bits & DML_USR)
77225655Skarels 		lcr |= DMZ_USRW;
77325655Skarels 	return (lcr);
77425224Smckusick }
77525224Smckusick 
77625224Smckusick /*
77725655Skarels  * Routine to convert modem status from dmz receive modem status
77825655Skarels  * and line control register to dm format.
77925655Skarels  * If dmz user modem read bit set, set DML_USR.
78025224Smckusick  */
78125655Skarels dmztodm(rms, lcr)
78225655Skarels 	register int rms, lcr;
78325224Smckusick {
78425224Smckusick 
78525655Skarels 	rms = ((rms & (DMZ_DSR|DMZ_RNG|DMZ_CAR|DMZ_CTS|DMF_SR)) >> 7) |
78625655Skarels 		((rms & DMZ_USRR) >> 1) | DML_LE;
78725655Skarels 	if (lcr & DMZ_DTR)
78825655Skarels 		rms |= DML_DTR;
78925655Skarels 	if (lcr & DMF_ST)
79025655Skarels 		rms |= DML_ST;
79125655Skarels 	if (lcr & DMZ_RTS)
79225655Skarels 		rms |= DML_RTS;
79325655Skarels 	return (rms);
79425224Smckusick }
79525224Smckusick #endif
796