xref: /csrg-svn/sys/vax/uba/dmz.c (revision 27051)
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*27051Skarels  *	@(#)dmz.c	6.7 (Berkeley) 04/12/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"
3326837Skarels #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);
213*27051Skarels #ifndef PORTSELECTOR
214*27051Skarels 		if (tp->t_ispeed == 0) {
215*27051Skarels #else
216*27051Skarels 			tp->t_state |= TS_HUPCLS;
217*27051Skarels #endif PORTSELECTOR
218*27051Skarels 			tp->t_ispeed = ISPEED;
219*27051Skarels 			tp->t_ospeed = ISPEED;
220*27051Skarels 			tp->t_flags = IFLAGS;
221*27051Skarels #ifndef PORTSELECTOR
222*27051Skarels 		}
223*27051Skarels #endif PORTSELECTOR
22425224Smckusick 		dmz_softc[unit].dmz_state = 0;
22525224Smckusick 	}
22625655Skarels 	dmzparam(unit);
22725224Smckusick 
22825224Smckusick 	/*
22925224Smckusick 	 * Wait for carrier, then process line discipline specific open.
23025224Smckusick 	 */
23125655Skarels 	if ((dmzmctl(unit, DMZ_ON, DMSET) & DMZ_CAR) ||
23225224Smckusick 	    (dmzsoftCAR[controller] & (1 << (unit % 24))))
23325224Smckusick 		tp->t_state |= TS_CARR_ON;
23425224Smckusick 	priority = spl5();
23525224Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
23625224Smckusick 		tp->t_state |= TS_WOPEN;
23725224Smckusick 		sleep((caddr_t) &tp->t_rawq, TTIPRI);
23825224Smckusick 	}
23925224Smckusick 	splx(priority);
24025224Smckusick 
24125435Skarels 	return ((*linesw[tp->t_line].l_open)(device, tp));
24225224Smckusick }
24325224Smckusick 
24425224Smckusick dmzparam(unit)
24525224Smckusick 	register int unit;
24625224Smckusick {
24725224Smckusick 	register struct tty *tp;
24825224Smckusick 	register struct dmzdevice *dmz_addr;
24925655Skarels 	register int line_parameters;
25025224Smckusick 	register int octet;
25125224Smckusick 	int priority;
25225224Smckusick 
25325224Smckusick 	octet = OCTET(unit);
25425224Smckusick 
25525224Smckusick 	tp = &dmz_tty[unit];
25625224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
25725224Smckusick 
25825224Smckusick 	priority = spl5();
25925224Smckusick 	if ((tp->t_ispeed) == 0) {
26025224Smckusick 		tp->t_state |= TS_HUPCLS;
26125224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
26225224Smckusick 		splx(priority);
26325224Smckusick 		return;
26425224Smckusick 	}
26525224Smckusick 
26625224Smckusick 	line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8);
26725224Smckusick 
26825224Smckusick 	if ((tp->t_ispeed) == B134)
26925224Smckusick 		line_parameters |= DMZ_6BT | DMZ_PEN;
27025655Skarels 	else if (tp->t_flags & (RAW | LITOUT | PASS8))
27125224Smckusick 		line_parameters |= DMZ_8BT;
27225224Smckusick 	else
27325224Smckusick 		line_parameters |= DMZ_7BT | DMZ_PEN;
27425224Smckusick 
27525224Smckusick 	if (tp->t_flags & EVENP)
27625224Smckusick 		line_parameters |= DMZ_EPR;
27725224Smckusick 	if ((tp->t_ospeed) == B110)
27825224Smckusick 		line_parameters |= DMZ_SCD;
27925224Smckusick 
28025224Smckusick 	line_parameters |= (unit & 07);
28125224Smckusick 
28225224Smckusick 	dmz_addr->octet[octet].octet_lprm = line_parameters;
28325224Smckusick 	splx(priority);
28425224Smckusick }
28525224Smckusick 
28625224Smckusick /* ARGSUSED */
28725224Smckusick dmzclose(device, flag)
28825224Smckusick 	dev_t device;
28925224Smckusick 	int flag;
29025224Smckusick {
29125224Smckusick 	register struct  tty *tp;
29225224Smckusick 	register int unit;
29325224Smckusick 
29425224Smckusick 	unit = minor(device);
29525224Smckusick 	tp = &dmz_tty[unit];
29625655Skarels 	(*linesw[tp->t_line].l_close)(tp);
29725224Smckusick 
29825224Smckusick 	/*
29925655Skarels 	 * Clear break, hang-up and close the modem.
30025224Smckusick 	 */
30125224Smckusick 	(void) dmzmctl(unit, DMZ_BRK, DMBIC);
30225224Smckusick 	if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
30325224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
30425224Smckusick 	ttyclose(tp);
30525224Smckusick 	return;
30625224Smckusick }
30725224Smckusick 
30825224Smckusick dmzreset(uban)
30925224Smckusick 	int uban;
31025224Smckusick {
31125224Smckusick 	register int controller, unit;
31225224Smckusick 	register struct tty *tp;
31325224Smckusick 	register struct uba_device *ui;
31425224Smckusick 	register struct dmzdevice *dmz_addr;
31525224Smckusick 	int i;
31625224Smckusick 	int octet;
31725224Smckusick 
31825224Smckusick 	for (controller = 0; controller < NDMZ; controller++) {
31925224Smckusick 		ui = dmzinfo[controller];
32025224Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
32125224Smckusick 			continue;
32225224Smckusick 		printf("dmz%d ", controller);
32325224Smckusick 		dmz_addr = (struct dmzdevice *) ui->ui_addr;
32425224Smckusick 
32526218Skarels 		if (dmz_ubinfo[uban]) {
32625435Skarels 			dmz_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
32725435Skarels 				nclist * sizeof(struct cblock), 0);
32826218Skarels 			cbase[uban] = UBAI_ADDR(dmz_ubinfo[uban]);
32925435Skarels 		}
33025435Skarels 
33125224Smckusick 		for (octet = 0; octet < 3; octet++)
33225224Smckusick 			if ((dmzact[controller] & (1 << octet)) != 0) {
33325224Smckusick 				dmz_addr->octet[octet].octet_csr |= DMZ_IE;
33425224Smckusick 				dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
33525224Smckusick 			}
33625224Smckusick 
33725224Smckusick 		unit = controller * 24;
33825224Smckusick 
33925224Smckusick 		/*
34025224Smckusick 		 * If a unit is open or waiting for open to complete,
34125224Smckusick 		 * reset it.
34225224Smckusick 		 */
34325224Smckusick 		for (i = 0; i < 24; i++) {
34425224Smckusick 			dmz_softc[unit].dmz_state = 0;
34525224Smckusick 			tp = &dmz_tty[unit];
34625224Smckusick 			if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) {
34725224Smckusick 				dmzparam(unit);
34825224Smckusick 				(void) dmzmctl(unit, DMZ_ON, DMSET);
34925224Smckusick 				tp->t_state &= ~TS_BUSY;
35025224Smckusick 				dmzstart(tp);
35125224Smckusick 			}
35225224Smckusick 			unit++;
35325224Smckusick 		}
35425224Smckusick 	}
35525224Smckusick 	return;
35625224Smckusick }
35725224Smckusick 
35825224Smckusick dmzread(device, uio)
35925224Smckusick 	dev_t device;
36025224Smckusick 	struct uio *uio;
36125224Smckusick {
36225224Smckusick 	register struct tty *tp;
36325224Smckusick 	int xstatus;
36425224Smckusick 
36525224Smckusick 	tp = &dmz_tty[minor(device)];
36625224Smckusick 	xstatus = (*linesw[tp->t_line].l_read)(tp, uio);
36725224Smckusick 	return (xstatus);
36825224Smckusick }
36925224Smckusick 
37025224Smckusick dmzwrite(device, uio)
37125224Smckusick 	dev_t device;
37225224Smckusick 	struct uio *uio;
37325224Smckusick {
37425224Smckusick 	register struct tty *tp;
37525224Smckusick 	int xstatus;
37625224Smckusick 
37725224Smckusick 	tp = &dmz_tty[minor(device)];
37825224Smckusick 	xstatus = (*linesw[tp->t_line].l_write)(tp, uio);
37925224Smckusick 	return (xstatus);
38025224Smckusick }
38125224Smckusick 
38225224Smckusick dmzrinta(controller)
38325224Smckusick 	int controller;
38425224Smckusick {
38525224Smckusick 	dmzrint(controller, 0);
38625224Smckusick }
38725224Smckusick 
38825224Smckusick dmzrintb(controller)
38925224Smckusick 	int controller;
39025224Smckusick {
39125224Smckusick 	dmzrint(controller, 1);
39225224Smckusick }
39325224Smckusick 
39425224Smckusick dmzrintc(controller)
39525224Smckusick 	int controller;
39625224Smckusick {
39725224Smckusick 	dmzrint(controller, 2);
39825224Smckusick }
39925224Smckusick 
40025224Smckusick dmzrint(controller, octet)
40125224Smckusick 	int controller;
40225224Smckusick 	register int octet;
40325224Smckusick {
40425224Smckusick 	register struct tty *tp;
40525224Smckusick 	register int character;
40625224Smckusick 	register struct dmzdevice *dmz_addr;
40725224Smckusick 	register struct tty *tp0;
40825224Smckusick 	register int unit;
40925224Smckusick 	register struct uba_device *ui;
41025396Skarels 	int overrun;
41125224Smckusick 
41225224Smckusick 	overrun = 0;
41325224Smckusick 	ui = dmzinfo[controller];
41425224Smckusick 	if (ui == 0 || ui->ui_alive == 0)
41525224Smckusick 		return;
41625224Smckusick 	dmz_addr = (struct dmzdevice *) ui->ui_addr;
41725224Smckusick 	tp0 = &dmz_tty[controller * 24];
41825224Smckusick 
41925224Smckusick 	while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) {
42025224Smckusick 		unit = (character >> 8) & 07;	/* unit is bits 8-10 of rb */
42125224Smckusick 		tp = tp0 + (octet * 8 + unit);
42225224Smckusick 
42326218Skarels 		if (character & DMZ_DSC) {
42425655Skarels 			dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | unit;
42525655Skarels 			if (dmz_addr->octet[octet].octet_rmstsc & DMZ_CAR)
42625396Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
427*27051Skarels 			else if ((dmzsoftCAR[controller] &
428*27051Skarels 			    (1 << (octet * 8 + unit))) == 0 &&
42926218Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
43025655Skarels 				(void)dmzmctl(tp - dmz_tty, DMZ_OFF, DMSET);
43125224Smckusick 			continue;
43225224Smckusick 		}
43325224Smckusick 
43425396Skarels 		if ((tp->t_state&TS_ISOPEN)==0) {
43525396Skarels 			wakeup((caddr_t)&tp->t_rawq);
43625396Skarels #ifdef PORTSELECTOR
43725396Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
43825396Skarels #endif
43925396Skarels 				continue;
44025224Smckusick 		}
44125224Smckusick 
44225224Smckusick 		if (character & DMZ_PE) {
44325224Smckusick 			if ((tp->t_flags & (EVENP | ODDP)) == EVENP ||
44425224Smckusick 			    (tp->t_flags & (EVENP | ODDP)) == ODDP)
44525224Smckusick 				continue;
44625224Smckusick 		}
44725224Smckusick 
44825224Smckusick 		if ((character & DMZ_DO) && overrun == 0) {
44925435Skarels 			log(LOG_WARNING, "dmz%d: silo overflow\n", controller);
45025224Smckusick 			overrun = 1;
45125224Smckusick 		}
45225224Smckusick 
45325224Smckusick 		if (character & DMZ_FE) {
45425224Smckusick 			if (tp->t_flags & RAW)
45525224Smckusick 				character = 0;
45625224Smckusick 			else
45725224Smckusick 				character = tp->t_intrc;
45825224Smckusick 		}
45925224Smckusick 
46025224Smckusick 		(*linesw[tp->t_line].l_rint)(character, tp);
46125224Smckusick 	}
46225224Smckusick 
46325224Smckusick 	return;
46425224Smckusick }
46525224Smckusick 
46625224Smckusick dmzxinta(controller)
46725224Smckusick 	int controller;
46825224Smckusick {
46925224Smckusick 	dmzxint(controller, 0);
47025224Smckusick }
47125224Smckusick 
47225224Smckusick dmzxintb(controller)
47325224Smckusick 	int controller;
47425224Smckusick {
47525224Smckusick 	dmzxint(controller, 1);
47625224Smckusick }
47725224Smckusick 
47825224Smckusick dmzxintc(controller)
47925224Smckusick 	int controller;
48025224Smckusick {
48125224Smckusick 	dmzxint(controller, 2);
48225224Smckusick }
48325224Smckusick 
48425224Smckusick dmzxint(controller, octet)
48525224Smckusick 	int controller;
48625224Smckusick 	register int octet;
48725224Smckusick {
48825224Smckusick 	register struct tty *tp;
48925224Smckusick 	register struct dmzdevice *dmz_addr;
49025224Smckusick 	register struct uba_device *ui;
49125224Smckusick 	register int unit, t;
49225224Smckusick 	int priority;
49325224Smckusick 
49425224Smckusick 	ui = dmzinfo[controller];
49525224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
49625224Smckusick 
49725224Smckusick 	priority = spl5();
49825224Smckusick 
49925224Smckusick 	while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) {
50025224Smckusick 		unit = controller * 24 + (octet * 8 + ((t>>8) & 07));
50125224Smckusick 		tp = &dmz_tty[unit];
50225224Smckusick 		tp->t_state &= ~TS_BUSY;
50325224Smckusick 
50425224Smckusick 		if (t & DMZ_NXM)
50525224Smckusick 			printf("dmz%d: NXM line %d\n", controller,
50625224Smckusick 				octet * 8 + (unit & 07));
50725224Smckusick 
50825224Smckusick 		if (tp->t_state & TS_FLUSH) {
50925224Smckusick 			tp->t_state &= ~TS_FLUSH;
51025224Smckusick 			dmz_addr->octet[octet].octet_csr =
51125224Smckusick 				DMZ_IE | IR_LCTMR | (unit & 07);
51225224Smckusick 			dmz_addr->octet[octet].octet_lctmr =
51325224Smckusick 				(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
51425224Smckusick 		} else
51525224Smckusick 			if (dmz_softc[unit].dmz_state & ST_DMA)
51625224Smckusick 				ndflush(&tp->t_outq, dmz_softc[unit].dmz_count);
51725224Smckusick 		dmz_softc[unit].dmz_state = 0;
51825224Smckusick 
51925224Smckusick 		if (tp->t_line)
52025224Smckusick 			(*linesw[tp->t_line].l_start)(tp);
52125224Smckusick 		else
52225224Smckusick 			dmzstart(tp);
52325224Smckusick 	}
52425224Smckusick 
52525224Smckusick 	splx(priority);
52625224Smckusick 	return;
52725224Smckusick }
52825224Smckusick 
52925224Smckusick dmzstart(tp)
53025224Smckusick 	register struct tty *tp;
53125224Smckusick {
53225224Smckusick 	register struct dmzdevice *dmz_addr;
53325224Smckusick 	register int unit, nch, room;
53425224Smckusick 	int controller, octet;
53525224Smckusick 	int priority, car, use_dma;
53625224Smckusick 	register int i;
53725224Smckusick 	register char *cp;
53825224Smckusick 
53925224Smckusick 	unit = minor(tp->t_dev);
54025224Smckusick 	controller = DMZ(unit);
54125224Smckusick 	octet = OCTET(unit);
54225224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
54325224Smckusick 
54425224Smckusick 	priority = spl5();
54525224Smckusick 
54625224Smckusick 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
54725224Smckusick 		goto out;
54825224Smckusick 
54925224Smckusick 	/*
55025224Smckusick 	 * If the transmitter has been disabled, reenable it.
55125224Smckusick 	 * If the transmitter was disabled before the xint (the
55225224Smckusick 	 * ST_INBUSY was still on), then reset the BUSY state and
55325224Smckusick 	 * we will wait for the interrupt.  If !TS_BUSY, we already
55425224Smckusick 	 * saw the interrupt so we can start another transmission.
55525224Smckusick 	 */
55625224Smckusick 	if (dmz_softc[unit].dmz_state & ST_TXOFF) {
55725224Smckusick 		dmz_addr->octet[octet].octet_csr =
55825224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
55925224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
56025224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
56125224Smckusick 		dmz_softc[unit].dmz_state &= ~ST_TXOFF;
56225224Smckusick 		if (dmz_softc[unit].dmz_state & ST_INBUSY) {
56325224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_INBUSY;
56425224Smckusick 			tp->t_state |= TS_BUSY;
56525224Smckusick 			goto out;
56625224Smckusick 		}
56725224Smckusick 	}
56825224Smckusick 
56925224Smckusick 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
57025224Smckusick 		if (tp->t_state & TS_ASLEEP) {
57125224Smckusick 			tp->t_state &= ~TS_ASLEEP;
57225224Smckusick 			wakeup((caddr_t)&tp->t_outq);
57325224Smckusick 		}
57425224Smckusick 		if (tp->t_wsel) {
57525224Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
57625224Smckusick 			tp->t_wsel = 0;
57725224Smckusick 			tp->t_state &= ~TS_WCOLL;
57825224Smckusick 		}
57925224Smckusick 	}
58025224Smckusick 
58125224Smckusick 	if (tp->t_outq.c_cc == 0)
58225224Smckusick 		goto out;
58325655Skarels 	if (tp->t_flags & (RAW | LITOUT | PASS8))
58425224Smckusick 		nch = ndqb(&tp->t_outq, 0);
58525224Smckusick 	else {
58625224Smckusick 		nch = ndqb(&tp->t_outq, 0200);
58725224Smckusick 		if (nch == 0) {
58825224Smckusick 			nch = getc(&tp->t_outq);
58925224Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6);
59025224Smckusick 			tp->t_state |= TS_TIMEOUT;
59125224Smckusick 			goto out;
59225224Smckusick 		}
59325224Smckusick 	}
59425224Smckusick 
59525224Smckusick 	/*
59625224Smckusick 	 * Should we use DMA or SILO mode?
59725224Smckusick 	 * If nch is greater than DO_DMA_COUNT then DMA.
59825224Smckusick 	 */
59925224Smckusick 	if (nch) {
60025224Smckusick 		dmz_addr->octet[octet].octet_csr =
60125224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
60225224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
60325224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
60425224Smckusick 		tp->t_state |= TS_BUSY;
60525224Smckusick 
60625224Smckusick 		use_dma = FALSE;
60725224Smckusick 		room = DMZ_SIZ;
60825224Smckusick 
60925224Smckusick 		if (nch > DO_DMA_COUNT)
61025224Smckusick 			use_dma = TRUE;
61125224Smckusick 
61225224Smckusick 		if (use_dma && dmz_dma_on) {
61325224Smckusick 			car = UBACVT(tp->t_outq.c_cf,
61425224Smckusick 				dmzinfo[controller]->ui_ubanum);
61525224Smckusick 			dmz_softc[unit].dmz_count = nch;
61625224Smckusick 			dmz_softc[unit].dmz_state |= ST_DMA;
61725224Smckusick 			dmz_addr->octet[octet].octet_csr =
61825224Smckusick 				DMZ_IE | IR_TBA | (unit & 07);
61925224Smckusick 			dmz_addr->octet[octet].octet_tba = car;
62025224Smckusick 			dmz_addr->octet[octet].octet_tcc =
62125224Smckusick 				((car >> 2) & 0xc000) | nch;
62225224Smckusick 		} else {
62325224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_DMA;
62425224Smckusick 			cp = tp->t_outq.c_cf;
62525224Smckusick 			nch = MIN(nch, room);
62625224Smckusick 			dmz_addr->octet[octet].octet_csr =
62725224Smckusick 				DMZ_IE | IR_TBUF | (unit & 07);
62825224Smckusick 			for (i = 0; i < nch; i++)
62925224Smckusick 				dmz_addr->octet[octet].octet_tbf = *cp++ ;
63025224Smckusick 			ndflush(&tp->t_outq, nch);
63125224Smckusick 		}
63225224Smckusick 	}
63325224Smckusick 
63425224Smckusick out:
63525224Smckusick 	splx(priority);
63625224Smckusick 	return;
63725224Smckusick }
63825224Smckusick 
63925224Smckusick /* ARGSUSED */
64025224Smckusick dmzstop(tp, flag)
64125224Smckusick 	register struct tty *tp;
64225224Smckusick {
64325224Smckusick 	register struct dmzdevice *dmz_addr;
64425224Smckusick 	register int unit, priority, octet;
64525224Smckusick 
64625224Smckusick 	priority = spl5();
64725224Smckusick 	dmz_addr = (struct dmzdevice *) tp->t_addr;
64825224Smckusick 	unit = minor(tp->t_dev);
64925224Smckusick 	octet = OCTET(unit);
65025224Smckusick 
65125224Smckusick 	dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE;
65225224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
65325224Smckusick 		(dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE);
65425224Smckusick 	dmz_softc[unit].dmz_state |= ST_TXOFF;
65525224Smckusick 	if ((tp->t_state & TS_TTSTOP) == 0) {
65625224Smckusick 		tp->t_state |= (TS_FLUSH | TS_BUSY);
65725224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
65825224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_FLS);
65925224Smckusick 	} else if (tp->t_state & TS_BUSY) {
66025224Smckusick 		dmz_softc[unit].dmz_state |= ST_INBUSY;
66125224Smckusick 		tp->t_state &= ~TS_BUSY;
66225224Smckusick 	}
66325224Smckusick 
66425224Smckusick 	splx(priority);
66525224Smckusick 	return;
66625224Smckusick }
66725224Smckusick 
66825224Smckusick /* ARGSUSED */
66925224Smckusick dmzioctl(device, command, data, flag)
67025224Smckusick 	dev_t device;
67125224Smckusick 	caddr_t data;
67225224Smckusick {
67325224Smckusick 	register struct tty *tp;
67425224Smckusick 	register int unit;
67525224Smckusick 	int error;
67625224Smckusick 
67725224Smckusick 	unit = minor(device);
67825224Smckusick 	tp = &dmz_tty[unit];
67925224Smckusick 
68025224Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag);
68125224Smckusick 	if (error >= 0)
68225224Smckusick 		return (error);
68325224Smckusick 	error = ttioctl(tp, command, data, flag);
68425224Smckusick 	if (error >= 0) {
68525655Skarels 		if (command == TIOCSETP || command == TIOCSETN ||
68625655Skarels 		    command == TIOCLSET || command == TIOCLBIS ||
68725655Skarels 		    command == TIOCLBIC)
68825224Smckusick 			dmzparam(unit);
68925224Smckusick 		return (error);
69025224Smckusick 	}
69125224Smckusick 
69225224Smckusick 	switch (command) {
69325224Smckusick 		case TIOCSBRK:
69425655Skarels 			(void) dmzmctl(unit, DMZ_BRK, DMBIS);
69525224Smckusick 			break;
69625224Smckusick 		case TIOCCBRK:
69725655Skarels 			(void) dmzmctl(unit, DMZ_BRK, DMBIC);
69825224Smckusick 			break;
69925224Smckusick 		case TIOCSDTR:
70025655Skarels 			(void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIS);
70125224Smckusick 			break;
70225224Smckusick 		case TIOCCDTR:
70325655Skarels 			(void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIC);
70425224Smckusick 			break;
70525224Smckusick 		case TIOCMSET:
70625655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMSET);
70725224Smckusick 			break;
70825224Smckusick 		case TIOCMBIS:
70925655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIS);
71025224Smckusick 			break;
71125224Smckusick 		case TIOCMBIC:
71225655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIC);
71325224Smckusick 			break;
71425224Smckusick 		case TIOCMGET:
71525655Skarels 			*(int *)data = dmzmctl(unit, 0, DMGET);
71625224Smckusick 			break;
71725224Smckusick 		default:
71825224Smckusick 			return (ENOTTY);
71925224Smckusick 	}
72025224Smckusick 	return (0);
72125224Smckusick }
72225224Smckusick 
72325655Skarels dmzmctl(unit, bits, how)
72425655Skarels 	register int unit;
72525224Smckusick 	int bits, how;
72625224Smckusick {
72725224Smckusick 	register struct dmzdevice *dmz_addr;
72825655Skarels 	register int modem_status, line_control;
72925224Smckusick 	int priority;
73025224Smckusick 	int octet;
73125224Smckusick 
73225224Smckusick 	octet = OCTET(unit);
73325655Skarels 	dmz_addr = (struct dmzdevice *) dmzinfo[DMZ(unit)]->ui_addr;
73425224Smckusick 
73525224Smckusick 	priority = spl5();
73625655Skarels 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | (unit & 07);
73725655Skarels 	modem_status = dmz_addr->octet[octet].octet_rmstsc & 0xff00;
73825224Smckusick 
73925224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
74025655Skarels 	line_control = dmz_addr->octet[octet].octet_lctmr;
74125224Smckusick 
74225224Smckusick 
74325224Smckusick 	switch (how) {
74425224Smckusick 		case DMSET:
74525655Skarels 			line_control = bits;
74625224Smckusick 			break;
74725224Smckusick 		case DMBIS:
74825655Skarels 			line_control |= bits;
74925224Smckusick 			break;
75025224Smckusick 		case DMBIC:
75125655Skarels 			line_control &= ~bits;
75225224Smckusick 			break;
75325224Smckusick 		case DMGET:
75425224Smckusick 			(void) splx(priority);
75525655Skarels 			return (dmztodm(modem_status, line_control));
75625224Smckusick 	}
75725224Smckusick 
75825224Smckusick 	dmz_addr->octet[octet].octet_csr =
75925224Smckusick 		DMZ_IE | IR_LCTMR | (unit & 07);
76025655Skarels 	dmz_addr->octet[octet].octet_lctmr = line_control;
76125224Smckusick 
76225655Skarels 	splx(priority);
76325224Smckusick 	return (modem_status);
76425224Smckusick }
76525224Smckusick 
76625224Smckusick /*
76725655Skarels  * Routine to convert modem status from dm to dmz lctmr format.
76825224Smckusick  */
76925224Smckusick dmtodmz(bits)
77025224Smckusick 	register int bits;
77125224Smckusick {
77225655Skarels 	register int lcr = DMZ_LCE;
77325224Smckusick 
77425655Skarels 	if (bits & DML_DTR)
77525655Skarels 		lcr |= DMZ_DTR;
77625655Skarels 	if (bits & DML_RTS)
77725655Skarels 		lcr |= DMZ_RTS;
77825655Skarels 	if (bits & DML_ST)
77925655Skarels 		lcr |= DMF_ST;
78025655Skarels 	if (bits & DML_USR)
78125655Skarels 		lcr |= DMZ_USRW;
78225655Skarels 	return (lcr);
78325224Smckusick }
78425224Smckusick 
78525224Smckusick /*
78625655Skarels  * Routine to convert modem status from dmz receive modem status
78725655Skarels  * and line control register to dm format.
78825655Skarels  * If dmz user modem read bit set, set DML_USR.
78925224Smckusick  */
79025655Skarels dmztodm(rms, lcr)
79125655Skarels 	register int rms, lcr;
79225224Smckusick {
79325224Smckusick 
79425655Skarels 	rms = ((rms & (DMZ_DSR|DMZ_RNG|DMZ_CAR|DMZ_CTS|DMF_SR)) >> 7) |
79525655Skarels 		((rms & DMZ_USRR) >> 1) | DML_LE;
79625655Skarels 	if (lcr & DMZ_DTR)
79725655Skarels 		rms |= DML_DTR;
79825655Skarels 	if (lcr & DMF_ST)
79925655Skarels 		rms |= DML_ST;
80025655Skarels 	if (lcr & DMZ_RTS)
80125655Skarels 		rms |= DML_RTS;
80225655Skarels 	return (rms);
80325224Smckusick }
80425224Smckusick #endif
805