xref: /csrg-svn/sys/vax/uba/dmz.c (revision 25396)
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*25396Skarels  *	@(#)dmz.c	6.2 (Berkeley) 11/04/85
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  *	NOTE: The modem control routines have NOT been tested yet!!!
1625224Smckusick  *
1725224Smckusick  * 9-Aug-85	Mike Meyer (mwm) at ucb
1825224Smckusick  *	Mangled into shape for 4.3.
1925224Smckusick  */
2025224Smckusick 
2125224Smckusick #include "dmz.h"
2225224Smckusick #if NDMZ > 0
2325224Smckusick 
2425224Smckusick 
2525224Smckusick #include "../machine/pte.h"
2625224Smckusick 
2725224Smckusick 
2825224Smckusick #include "bk.h"
2925224Smckusick #include "uba.h"
3025224Smckusick #include "param.h"
3125224Smckusick #include "conf.h"
3225224Smckusick #include "dir.h"
3325224Smckusick #include "user.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"
4425224Smckusick 
4525224Smckusick #include "ubareg.h"
4625224Smckusick #include "ubavar.h"
4725224Smckusick #include "dmzreg.h"
4825224Smckusick 
4925224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint();
5025224Smckusick struct uba_device *dmzinfo[NDMZ];
5125224Smckusick u_short dmzstd[] = {0, 0};
5225224Smckusick struct uba_driver dmzdriver = {
5325224Smckusick 	dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo
5425224Smckusick };
5525224Smckusick 
5625224Smckusick #define	NDMZLINES	(NDMZ*24)
5725224Smckusick 
5825224Smckusick int ttrstrt();
5925224Smckusick struct tty dmz_tty[NDMZLINES];
6025224Smckusick 
6125224Smckusick int dmzsoftCAR[NDMZ];
6225224Smckusick 
6325224Smckusick struct {
6425224Smckusick 	char dmz_state;		/* dmz state */
6525224Smckusick 	int dmz_count;		/* dmz dma count */
6625224Smckusick } dmz_softc[NDMZ*24];
6725224Smckusick 
6825224Smckusick #define	ST_TXOFF	(0x01)	/* transmission turned off (^S) */
6925224Smckusick #define	ST_DMA		(0x02)	/* dma inprogress */
7025224Smckusick #define	ST_INBUSY	(0x04)	/* stop transmission in busy */
7125224Smckusick 
7225224Smckusick char dmz_speeds[] = {
7325224Smckusick 	0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0
7425224Smckusick };
7525224Smckusick 
76*25396Skarels #ifndef	PORTSELECTOR
77*25396Skarels #define	ISPEED	B9600
78*25396Skarels #define	IFLAGS	(EVENP|ODDP|ECHO)
79*25396Skarels #else
80*25396Skarels #define	ISPEED	B4800
81*25396Skarels #define	IFLAGS	(EVENP|ODDP)
82*25396Skarels #endif
83*25396Skarels 
8425224Smckusick #ifndef lint
8525224Smckusick int ndmz = NDMZLINES;		/* Used by pstat/iostat */
8625224Smckusick #endif
8725224Smckusick 
8825224Smckusick short dmzact[NDMZ];		/* Mask of active octets on the dmz */
8925224Smckusick int dmzstart();
9025224Smckusick 
9125224Smckusick /*
9225224Smckusick  * SILO_TIMEOUT represents the number of milliseconds characters can sit
9325224Smckusick  * in the input silo without causing an interrupt.  If data overruns or
9425224Smckusick  * slow XON/XOFF occur, set it lower but AT LEAST equal to 1.
9525224Smckusick  */
9625224Smckusick #define	SILO_TIMEOUT	(3)
9725224Smckusick 
9825224Smckusick /*
9925224Smckusick  * DO_DMA_COUNT represents the threshold of the number of output
10025224Smckusick  * characters beyond which the driver uses DMA mode.
10125224Smckusick  */
10225224Smckusick #define	DO_DMA_COUNT	(10)
10325224Smckusick 
10425224Smckusick #define	TRUE		(1)
10525224Smckusick #define	FALSE		(0)
10625224Smckusick 
10725224Smckusick static int cbase[NUBA];		/* base address in unibus map */
10825224Smckusick int dmz_ubinfo[NUBA];		/* info about allocated unibus map */
10925224Smckusick 
11025224Smckusick #define	UBACVT(x, uban)	    (cbase[uban] + ((x) - (char *)cfree))
11125224Smckusick 
11225224Smckusick /* These flags are for debugging purposes only */
11325224Smckusick int dmz_dma_on = 1;
11425224Smckusick int dmz_debug_level;
11525224Smckusick 
11625224Smckusick dmzprobe(reg)
11725224Smckusick 	caddr_t reg;
11825224Smckusick {
11925224Smckusick 	register int br, cvec;
12025224Smckusick 	register struct dmzdevice *dmz_addr;
12125224Smckusick 	register unsigned int a;
12225224Smckusick 
12325224Smckusick 	dmz_addr = (struct dmzdevice *)reg;
12425224Smckusick 
12525224Smckusick #ifdef lint
12625224Smckusick 	br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0);
12725224Smckusick 	dmzrinta(0); dmzrintb(0); dmzrintc(0);
12825224Smckusick #endif
12925224Smckusick 
13025224Smckusick 	br = 0x15;
13125224Smckusick 
13225224Smckusick 	a = dmz_addr->dmz_config;
13325224Smckusick 	if (((a>>12) & ~DMZ_INTERFACE) != 0) {
13425224Smckusick 		printf("	Unknown interface type\n");
13525224Smckusick 		return (0);
13625224Smckusick 	}
13725224Smckusick 	if (((a>>8) & DMZ_NOC_MASK) != 3) {
13825224Smckusick 		printf("	Not all octets are available\n");
13925224Smckusick 		return (0);
14025224Smckusick 	}
14125224Smckusick 
14225224Smckusick 	cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6);
14325224Smckusick 	dmz_addr->dmz_config = cvec >> 2;
14425224Smckusick 
14525224Smckusick 	return (sizeof(struct dmzdevice));
14625224Smckusick }
14725224Smckusick 
14825224Smckusick dmzattach(ui)
14925224Smckusick 	struct uba_device *ui;
15025224Smckusick {
15125224Smckusick 	dmzsoftCAR[ui->ui_unit] = ui->ui_flags;
15225224Smckusick 	return;
15325224Smckusick }
15425224Smckusick 
15525224Smckusick /* ARGSUSED */
15625224Smckusick dmzopen(device, flag)
15725224Smckusick 	dev_t device;
15825224Smckusick 	int flag;
15925224Smckusick {
16025224Smckusick 	register struct tty *tp;
16125224Smckusick 	register int unit, controller;
16225224Smckusick 	register struct dmzdevice *dmz_addr;
16325224Smckusick 	register struct uba_device *ui;
16425224Smckusick 	int priority;
16525224Smckusick 	int xstatus;
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 	tp->t_state |= TS_WOPEN;
18625224Smckusick 
18725224Smckusick 	/*
18825224Smckusick 	 * Set up Unibus map registers.  Block uba resets, which can
18925224Smckusick 	 * clear the state.
19025224Smckusick 	 */
19125224Smckusick 	priority = spl5();
19225224Smckusick 	if (dmz_ubinfo[ui->ui_ubanum] == 0) {
19325224Smckusick 		dmz_ubinfo[ui->ui_ubanum] =
19425224Smckusick 			uballoc(ui->ui_ubanum, (caddr_t)cfree,
19525224Smckusick 				nclist * sizeof(struct cblock), 0);
19625224Smckusick 		if (dmz_ubinfo[ui->ui_ubanum] == 0) {
19725224Smckusick 			splx(priority);
19825224Smckusick 			printf("dmz: insufficient unibus map regs\n");
19925224Smckusick 			return (-1); /* Is this the right thing to return? */
20025224Smckusick 		}
20125224Smckusick 		cbase[ui->ui_ubanum] = dmz_ubinfo[ui->ui_ubanum] & 0x3ffff;
20225224Smckusick 	}
20325224Smckusick 
20425224Smckusick 	if ((dmzact[controller] & (1 << octet)) == 0) {
20525224Smckusick 		dmz_addr->octet[octet].octet_csr |= DMZ_IE;
20625224Smckusick 		dmzact[controller] |= 1 << octet;
20725224Smckusick 		dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
20825224Smckusick 	}
20925224Smckusick 
21025224Smckusick 	splx(priority);
21125224Smckusick 
21225224Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
21325224Smckusick 		ttychars(tp);
214*25396Skarels 		tp->t_ispeed = tp->t_ospeed = ISPEED;
215*25396Skarels 		tp->t_flags = IFLAGS;
21625224Smckusick 		dmzparam(unit);
21725224Smckusick 		dmz_softc[unit].dmz_state = 0;
21825224Smckusick 	}
21925224Smckusick 
22025224Smckusick 	/*
22125224Smckusick 	 * Wait for carrier, then process line discipline specific open.
22225224Smckusick 	 */
22325224Smckusick 	if ((dmzmctl(device, DMZ_ON, DMSET) & (DMZ_CAR << 8)) ||
22425224Smckusick 	    (dmzsoftCAR[controller] & (1 << (unit % 24))))
22525224Smckusick 		tp->t_state |= TS_CARR_ON;
22625224Smckusick 	priority = spl5();
22725224Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
22825224Smckusick 		tp->t_state |= TS_WOPEN;
22925224Smckusick 		sleep((caddr_t) &tp->t_rawq, TTIPRI);
23025224Smckusick 	}
23125224Smckusick 	splx(priority);
23225224Smckusick 
23325224Smckusick 	xstatus = (*linesw[tp->t_line].l_open)(device, tp);
23425224Smckusick 	return (xstatus);
23525224Smckusick }
23625224Smckusick 
23725224Smckusick dmzparam(unit)
23825224Smckusick 	register int unit;
23925224Smckusick {
24025224Smckusick 	register struct tty *tp;
24125224Smckusick 	register struct dmzdevice *dmz_addr;
24225224Smckusick 	register int line_parameters, line_control;
24325224Smckusick 	register int octet;
24425224Smckusick 	int priority;
24525224Smckusick 
24625224Smckusick 	octet = OCTET(unit);
24725224Smckusick 
24825224Smckusick 	tp = &dmz_tty[unit];
24925224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
25025224Smckusick 
25125224Smckusick 	priority = spl5();
25225224Smckusick 	if ((tp->t_ispeed) == 0) {
25325224Smckusick 		tp->t_state |= TS_HUPCLS;
25425224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
25525224Smckusick 		splx(priority);
25625224Smckusick 		return;
25725224Smckusick 	}
25825224Smckusick 
25925224Smckusick 	line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8);
26025224Smckusick 	line_control = DMZ_LCE;
26125224Smckusick 
26225224Smckusick 	if ((tp->t_ispeed) == B134)
26325224Smckusick 		line_parameters |= DMZ_6BT | DMZ_PEN;
26425224Smckusick 	else if (tp->t_flags & (RAW | LITOUT))
26525224Smckusick 		line_parameters |= DMZ_8BT;
26625224Smckusick 	else
26725224Smckusick 		line_parameters |= DMZ_7BT | DMZ_PEN;
26825224Smckusick 
26925224Smckusick 	if (tp->t_flags & EVENP)
27025224Smckusick 		line_parameters |= DMZ_EPR;
27125224Smckusick 	if ((tp->t_ospeed) == B110)
27225224Smckusick 		line_parameters |= DMZ_SCD;
27325224Smckusick 
27425224Smckusick 	line_parameters |= (unit & 07);
27525224Smckusick 
27625224Smckusick 	dmz_addr->octet[octet].octet_lprm = line_parameters;
27725224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
27825224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
27925224Smckusick 	    (dmz_addr->octet[octet].octet_lctmr | (line_control & 0xff));
28025224Smckusick 
28125224Smckusick 	splx(priority);
28225224Smckusick 	return;
28325224Smckusick }
28425224Smckusick 
28525224Smckusick /* ARGSUSED */
28625224Smckusick dmzclose(device, flag)
28725224Smckusick 	dev_t device;
28825224Smckusick 	int flag;
28925224Smckusick {
29025224Smckusick 	register struct  tty *tp;
29125224Smckusick 	register int unit;
29225224Smckusick 
29325224Smckusick 	unit = minor(device);
29425224Smckusick 	tp = &dmz_tty[unit];
29525224Smckusick 
29625224Smckusick 	/*
29725224Smckusick 	 * Break, hang-up and close the modem.
29825224Smckusick 	 */
29925224Smckusick 	(void) dmzmctl(unit, DMZ_BRK, DMBIC);
30025224Smckusick 	if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
30125224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
30225224Smckusick 	ttyclose(tp);
30325224Smckusick 	return;
30425224Smckusick }
30525224Smckusick 
30625224Smckusick dmzreset(uban)
30725224Smckusick 	int uban;
30825224Smckusick {
30925224Smckusick 	register int controller, unit;
31025224Smckusick 	register struct tty *tp;
31125224Smckusick 	register struct uba_device *ui;
31225224Smckusick 	register struct dmzdevice *dmz_addr;
31325224Smckusick 	int i;
31425224Smckusick 	int octet;
31525224Smckusick 
31625224Smckusick 	if (dmz_ubinfo[uban] == 0)
31725224Smckusick 		return;
31825224Smckusick 
31925224Smckusick 	dmz_ubinfo[uban] = uballoc(uban, (caddr_t) cfree, nclist * sizeof(struct cblock), 0);
32025224Smckusick 	cbase[uban] = dmz_ubinfo[uban] & 0x3ffff;
32125224Smckusick 
32225224Smckusick 	for (controller = 0; controller < NDMZ; controller++) {
32325224Smckusick 		ui = dmzinfo[controller];
32425224Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
32525224Smckusick 			continue;
32625224Smckusick 		printf("dmz%d ", controller);
32725224Smckusick 		dmz_addr = (struct dmzdevice *) ui->ui_addr;
32825224Smckusick 
32925224Smckusick 		for (octet = 0; octet < 3; octet++)
33025224Smckusick 			if ((dmzact[controller] & (1 << octet)) != 0) {
33125224Smckusick 				dmz_addr->octet[octet].octet_csr |= DMZ_IE;
33225224Smckusick 				dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
33325224Smckusick 			}
33425224Smckusick 
33525224Smckusick 		unit = controller * 24;
33625224Smckusick 
33725224Smckusick 		/*
33825224Smckusick 		 * If a unit is open or waiting for open to complete,
33925224Smckusick 		 * reset it.
34025224Smckusick 		 */
34125224Smckusick 		for (i = 0; i < 24; i++) {
34225224Smckusick 			dmz_softc[unit].dmz_state = 0;
34325224Smckusick 			tp = &dmz_tty[unit];
34425224Smckusick 			if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) {
34525224Smckusick 				dmzparam(unit);
34625224Smckusick 				(void) dmzmctl(unit, DMZ_ON, DMSET);
34725224Smckusick 				tp->t_state &= ~TS_BUSY;
34825224Smckusick 				dmzstart(tp);
34925224Smckusick 			}
35025224Smckusick 			unit++;
35125224Smckusick 		}
35225224Smckusick 	}
35325224Smckusick 	return;
35425224Smckusick }
35525224Smckusick 
35625224Smckusick dmzread(device, uio)
35725224Smckusick 	dev_t device;
35825224Smckusick 	struct uio *uio;
35925224Smckusick {
36025224Smckusick 	register struct tty *tp;
36125224Smckusick 	int xstatus;
36225224Smckusick 
36325224Smckusick 	tp = &dmz_tty[minor(device)];
36425224Smckusick 	xstatus = (*linesw[tp->t_line].l_read)(tp, uio);
36525224Smckusick 	return (xstatus);
36625224Smckusick }
36725224Smckusick 
36825224Smckusick dmzwrite(device, uio)
36925224Smckusick 	dev_t device;
37025224Smckusick 	struct uio *uio;
37125224Smckusick {
37225224Smckusick 	register struct tty *tp;
37325224Smckusick 	int xstatus;
37425224Smckusick 
37525224Smckusick 	tp = &dmz_tty[minor(device)];
37625224Smckusick 	xstatus = (*linesw[tp->t_line].l_write)(tp, uio);
37725224Smckusick 	return (xstatus);
37825224Smckusick }
37925224Smckusick 
38025224Smckusick dmzrinta(controller)
38125224Smckusick 	int controller;
38225224Smckusick {
38325224Smckusick 	dmzrint(controller, 0);
38425224Smckusick }
38525224Smckusick 
38625224Smckusick dmzrintb(controller)
38725224Smckusick 	int controller;
38825224Smckusick {
38925224Smckusick 	dmzrint(controller, 1);
39025224Smckusick }
39125224Smckusick 
39225224Smckusick dmzrintc(controller)
39325224Smckusick 	int controller;
39425224Smckusick {
39525224Smckusick 	dmzrint(controller, 2);
39625224Smckusick }
39725224Smckusick 
39825224Smckusick dmzrint(controller, octet)
39925224Smckusick 	int controller;
40025224Smckusick 	register int octet;
40125224Smckusick {
40225224Smckusick 	register struct tty *tp;
40325224Smckusick 	register int character;
40425224Smckusick 	register struct dmzdevice *dmz_addr;
40525224Smckusick 	register struct tty *tp0;
40625224Smckusick 	register int unit;
40725224Smckusick 	register struct uba_device *ui;
408*25396Skarels 	int overrun;
40925224Smckusick 
41025224Smckusick 	overrun = 0;
41125224Smckusick 	ui = dmzinfo[controller];
41225224Smckusick 	if (ui == 0 || ui->ui_alive == 0)
41325224Smckusick 		return;
41425224Smckusick 	dmz_addr = (struct dmzdevice *) ui->ui_addr;
41525224Smckusick 	tp0 = &dmz_tty[controller * 24];
41625224Smckusick 
41725224Smckusick 	while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) {
41825224Smckusick 		unit = (character >> 8) & 07;	/* unit is bits 8-10 of rb */
41925224Smckusick 		tp = tp0 + (octet * 8 + unit);
42025224Smckusick 
421*25396Skarels 		if (character & DMZ_DSC &&
422*25396Skarels 		    (dmzsoftCAR[controller] & (1 << (octet * 8 + unit))) == 0) {
423*25396Skarels 			dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | unit;
424*25396Skarels 			if (dmz_addr->octet[octet].octet_rms & DMZ_CAR)
425*25396Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
426*25396Skarels 			else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
427*25396Skarels 				dmz_addr->octet[octet].octet_csr =
428*25396Skarels 				   DMZ_IE | IR_LCTMR | unit;
429*25396Skarels 				dmz_addr->octet[octet].octet_lctmr =
430*25396Skarels 				   dmz_addr->octet[octet].octet_lctmr &
431*25396Skarels 				   ((DMZ_OFF<<8) | 0xff);
43225224Smckusick 			}
43325224Smckusick 			continue;
43425224Smckusick 		}
43525224Smckusick 
436*25396Skarels 		if ((tp->t_state&TS_ISOPEN)==0) {
437*25396Skarels 			wakeup((caddr_t)&tp->t_rawq);
438*25396Skarels #ifdef PORTSELECTOR
439*25396Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
440*25396Skarels #endif
441*25396Skarels 				continue;
44225224Smckusick 		}
44325224Smckusick 
44425224Smckusick 		if (character & DMZ_PE) {
44525224Smckusick 			if ((tp->t_flags & (EVENP | ODDP)) == EVENP ||
44625224Smckusick 			    (tp->t_flags & (EVENP | ODDP)) == ODDP)
44725224Smckusick 				continue;
44825224Smckusick 		}
44925224Smckusick 
45025224Smckusick 		if ((character & DMZ_DO) && overrun == 0) {
45125224Smckusick 			printf("dmz%d: silo overflow\n", controller);
45225224Smckusick 			overrun = 1;
45325224Smckusick 		}
45425224Smckusick 
45525224Smckusick 		if (character & DMZ_FE) {
45625224Smckusick 			if (tp->t_flags & RAW)
45725224Smckusick 				character = 0;
45825224Smckusick 			else
45925224Smckusick 				character = tp->t_intrc;
46025224Smckusick 		}
46125224Smckusick 
46225224Smckusick 		(*linesw[tp->t_line].l_rint)(character, tp);
46325224Smckusick 	}
46425224Smckusick 
46525224Smckusick 	return;
46625224Smckusick }
46725224Smckusick 
46825224Smckusick dmzxinta(controller)
46925224Smckusick 	int controller;
47025224Smckusick {
47125224Smckusick 	dmzxint(controller, 0);
47225224Smckusick }
47325224Smckusick 
47425224Smckusick dmzxintb(controller)
47525224Smckusick 	int controller;
47625224Smckusick {
47725224Smckusick 	dmzxint(controller, 1);
47825224Smckusick }
47925224Smckusick 
48025224Smckusick dmzxintc(controller)
48125224Smckusick 	int controller;
48225224Smckusick {
48325224Smckusick 	dmzxint(controller, 2);
48425224Smckusick }
48525224Smckusick 
48625224Smckusick dmzxint(controller, octet)
48725224Smckusick 	int controller;
48825224Smckusick 	register int octet;
48925224Smckusick {
49025224Smckusick 	register struct tty *tp;
49125224Smckusick 	register struct dmzdevice *dmz_addr;
49225224Smckusick 	register struct uba_device *ui;
49325224Smckusick 	register int unit, t;
49425224Smckusick 	int priority;
49525224Smckusick 
49625224Smckusick 	ui = dmzinfo[controller];
49725224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
49825224Smckusick 
49925224Smckusick 	priority = spl5();
50025224Smckusick 
50125224Smckusick 	while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) {
50225224Smckusick 		unit = controller * 24 + (octet * 8 + ((t>>8) & 07));
50325224Smckusick 		tp = &dmz_tty[unit];
50425224Smckusick 		tp->t_state &= ~TS_BUSY;
50525224Smckusick 
50625224Smckusick 		if (t & DMZ_NXM)
50725224Smckusick 			printf("dmz%d: NXM line %d\n", controller,
50825224Smckusick 				octet * 8 + (unit & 07));
50925224Smckusick 
51025224Smckusick 		if (tp->t_state & TS_FLUSH) {
51125224Smckusick 			tp->t_state &= ~TS_FLUSH;
51225224Smckusick 			dmz_addr->octet[octet].octet_csr =
51325224Smckusick 				DMZ_IE | IR_LCTMR | (unit & 07);
51425224Smckusick 			dmz_addr->octet[octet].octet_lctmr =
51525224Smckusick 				(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
51625224Smckusick 		} else
51725224Smckusick 			if (dmz_softc[unit].dmz_state & ST_DMA)
51825224Smckusick 				ndflush(&tp->t_outq, dmz_softc[unit].dmz_count);
51925224Smckusick 		dmz_softc[unit].dmz_state = 0;
52025224Smckusick 
52125224Smckusick 		if (tp->t_line)
52225224Smckusick 			(*linesw[tp->t_line].l_start)(tp);
52325224Smckusick 		else
52425224Smckusick 			dmzstart(tp);
52525224Smckusick 	}
52625224Smckusick 
52725224Smckusick 	splx(priority);
52825224Smckusick 	return;
52925224Smckusick }
53025224Smckusick 
53125224Smckusick dmzstart(tp)
53225224Smckusick 	register struct tty *tp;
53325224Smckusick {
53425224Smckusick 	register struct dmzdevice *dmz_addr;
53525224Smckusick 	register int unit, nch, room;
53625224Smckusick 	int controller, octet;
53725224Smckusick 	int priority, car, use_dma;
53825224Smckusick 	register int i;
53925224Smckusick 	register char *cp;
54025224Smckusick 
54125224Smckusick 	unit = minor(tp->t_dev);
54225224Smckusick 	controller = DMZ(unit);
54325224Smckusick 	octet = OCTET(unit);
54425224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
54525224Smckusick 
54625224Smckusick 	priority = spl5();
54725224Smckusick 
54825224Smckusick 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
54925224Smckusick 		goto out;
55025224Smckusick 
55125224Smckusick 	/*
55225224Smckusick 	 * If the transmitter has been disabled, reenable it.
55325224Smckusick 	 * If the transmitter was disabled before the xint (the
55425224Smckusick 	 * ST_INBUSY was still on), then reset the BUSY state and
55525224Smckusick 	 * we will wait for the interrupt.  If !TS_BUSY, we already
55625224Smckusick 	 * saw the interrupt so we can start another transmission.
55725224Smckusick 	 */
55825224Smckusick 	if (dmz_softc[unit].dmz_state & ST_TXOFF) {
55925224Smckusick 		dmz_addr->octet[octet].octet_csr =
56025224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
56125224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
56225224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
56325224Smckusick 		dmz_softc[unit].dmz_state &= ~ST_TXOFF;
56425224Smckusick 		if (dmz_softc[unit].dmz_state & ST_INBUSY) {
56525224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_INBUSY;
56625224Smckusick 			tp->t_state |= TS_BUSY;
56725224Smckusick 			goto out;
56825224Smckusick 		}
56925224Smckusick 	}
57025224Smckusick 
57125224Smckusick 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
57225224Smckusick 		if (tp->t_state & TS_ASLEEP) {
57325224Smckusick 			tp->t_state &= ~TS_ASLEEP;
57425224Smckusick 			wakeup((caddr_t)&tp->t_outq);
57525224Smckusick 		}
57625224Smckusick 		if (tp->t_wsel) {
57725224Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
57825224Smckusick 			tp->t_wsel = 0;
57925224Smckusick 			tp->t_state &= ~TS_WCOLL;
58025224Smckusick 		}
58125224Smckusick 	}
58225224Smckusick 
58325224Smckusick 	if (tp->t_outq.c_cc == 0)
58425224Smckusick 		goto out;
58525224Smckusick 	if (tp->t_flags & (RAW | LITOUT))
58625224Smckusick 		nch = ndqb(&tp->t_outq, 0);
58725224Smckusick 	else {
58825224Smckusick 		nch = ndqb(&tp->t_outq, 0200);
58925224Smckusick 		if (nch == 0) {
59025224Smckusick 			nch = getc(&tp->t_outq);
59125224Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6);
59225224Smckusick 			tp->t_state |= TS_TIMEOUT;
59325224Smckusick 			goto out;
59425224Smckusick 		}
59525224Smckusick 	}
59625224Smckusick 
59725224Smckusick 	/*
59825224Smckusick 	 * Should we use DMA or SILO mode?
59925224Smckusick 	 * If nch is greater than DO_DMA_COUNT then DMA.
60025224Smckusick 	 */
60125224Smckusick 	if (nch) {
60225224Smckusick 		dmz_addr->octet[octet].octet_csr =
60325224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
60425224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
60525224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
60625224Smckusick 		tp->t_state |= TS_BUSY;
60725224Smckusick 
60825224Smckusick 		use_dma = FALSE;
60925224Smckusick 		room = DMZ_SIZ;
61025224Smckusick 
61125224Smckusick 		if (nch > DO_DMA_COUNT)
61225224Smckusick 			use_dma = TRUE;
61325224Smckusick 
61425224Smckusick 		if (use_dma && dmz_dma_on) {
61525224Smckusick 			car = UBACVT(tp->t_outq.c_cf,
61625224Smckusick 				dmzinfo[controller]->ui_ubanum);
61725224Smckusick 			dmz_softc[unit].dmz_count = nch;
61825224Smckusick 			dmz_softc[unit].dmz_state |= ST_DMA;
61925224Smckusick 			dmz_addr->octet[octet].octet_csr =
62025224Smckusick 				DMZ_IE | IR_TBA | (unit & 07);
62125224Smckusick 			dmz_addr->octet[octet].octet_tba = car;
62225224Smckusick 			dmz_addr->octet[octet].octet_tcc =
62325224Smckusick 				((car >> 2) & 0xc000) | nch;
62425224Smckusick 		} else {
62525224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_DMA;
62625224Smckusick 			cp = tp->t_outq.c_cf;
62725224Smckusick 			nch = MIN(nch, room);
62825224Smckusick 			dmz_addr->octet[octet].octet_csr =
62925224Smckusick 				DMZ_IE | IR_TBUF | (unit & 07);
63025224Smckusick 			for (i = 0; i < nch; i++)
63125224Smckusick 				dmz_addr->octet[octet].octet_tbf = *cp++ ;
63225224Smckusick 			ndflush(&tp->t_outq, nch);
63325224Smckusick 		}
63425224Smckusick 	}
63525224Smckusick 
63625224Smckusick out:
63725224Smckusick 	splx(priority);
63825224Smckusick 	return;
63925224Smckusick }
64025224Smckusick 
64125224Smckusick /* ARGSUSED */
64225224Smckusick dmzstop(tp, flag)
64325224Smckusick 	register struct tty *tp;
64425224Smckusick {
64525224Smckusick 	register struct dmzdevice *dmz_addr;
64625224Smckusick 	register int unit, priority, octet;
64725224Smckusick 
64825224Smckusick 	priority = spl5();
64925224Smckusick 	dmz_addr = (struct dmzdevice *) tp->t_addr;
65025224Smckusick 	unit = minor(tp->t_dev);
65125224Smckusick 	octet = OCTET(unit);
65225224Smckusick 
65325224Smckusick 	dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE;
65425224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
65525224Smckusick 		(dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE);
65625224Smckusick 	dmz_softc[unit].dmz_state |= ST_TXOFF;
65725224Smckusick 	if ((tp->t_state & TS_TTSTOP) == 0) {
65825224Smckusick 		tp->t_state |= (TS_FLUSH | TS_BUSY);
65925224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
66025224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_FLS);
66125224Smckusick 	} else if (tp->t_state & TS_BUSY) {
66225224Smckusick 		dmz_softc[unit].dmz_state |= ST_INBUSY;
66325224Smckusick 		tp->t_state &= ~TS_BUSY;
66425224Smckusick 	}
66525224Smckusick 
66625224Smckusick 	splx(priority);
66725224Smckusick 	return;
66825224Smckusick }
66925224Smckusick 
67025224Smckusick /* ARGSUSED */
67125224Smckusick dmzioctl(device, command, data, flag)
67225224Smckusick 	dev_t device;
67325224Smckusick 	caddr_t data;
67425224Smckusick {
67525224Smckusick 	register struct tty *tp;
67625224Smckusick 	register int unit;
67725224Smckusick 	int error;
67825224Smckusick 
67925224Smckusick 	unit = minor(device);
68025224Smckusick 	tp = &dmz_tty[unit];
68125224Smckusick 
68225224Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag);
68325224Smckusick 	if (error >= 0)
68425224Smckusick 		return (error);
68525224Smckusick 	error = ttioctl(tp, command, data, flag);
68625224Smckusick 	if (error >= 0) {
68725224Smckusick 		if (command == TIOCSETP || command == TIOCSETN)
68825224Smckusick 			dmzparam(unit);
68925224Smckusick 		return (error);
69025224Smckusick 	}
69125224Smckusick 
69225224Smckusick 	switch (command) {
69325224Smckusick 		case TIOCSBRK:
69425224Smckusick 			(void) dmzmctl(device, DMZ_BRK, DMBIS);
69525224Smckusick 			break;
69625224Smckusick 		case TIOCCBRK:
69725224Smckusick 			(void) dmzmctl(device, DMZ_BRK, DMBIC);
69825224Smckusick 			break;
69925224Smckusick 		case TIOCSDTR:
70025224Smckusick 			(void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIS);
70125224Smckusick 			break;
70225224Smckusick 		case TIOCCDTR:
70325224Smckusick 			(void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIC);
70425224Smckusick 			break;
70525224Smckusick 		case TIOCMSET:
70625224Smckusick 			(void) dmzmctl(device, dmtodmz(*(int *)data), DMSET);
70725224Smckusick 			break;
70825224Smckusick 		case TIOCMBIS:
70925224Smckusick 			(void) dmzmctl(device, dmtodmz(*(int *)data), DMBIS);
71025224Smckusick 			break;
71125224Smckusick 		case TIOCMBIC:
71225224Smckusick 			(void) dmzmctl(device, dmtodmz(*(int *)data), DMBIC);
71325224Smckusick 			break;
71425224Smckusick 		case TIOCMGET:
71525224Smckusick 			*(int *)data = dmztodm(dmzmctl(device, 0, DMGET));
71625224Smckusick 			break;
71725224Smckusick 		default:
71825224Smckusick 			return (ENOTTY);
71925224Smckusick 	}
72025224Smckusick 	return (0);
72125224Smckusick }
72225224Smckusick 
72325224Smckusick dmzmctl(device, bits, how)
72425224Smckusick 	dev_t device;
72525224Smckusick 	int bits, how;
72625224Smckusick {
72725224Smckusick 	register struct dmzdevice *dmz_addr;
72825224Smckusick 	register int unit, modem_status, line_control;
72925224Smckusick 	register int temp;
73025224Smckusick 	int priority;
73125224Smckusick 	int octet;
73225224Smckusick 
73325224Smckusick 	unit = minor(device);
73425224Smckusick 	octet = OCTET(unit);
73525224Smckusick 	dmz_addr = (struct dmzdevice *) dmz_tty[unit].t_addr;
73625224Smckusick 
73725224Smckusick 	priority = spl5();
73825224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | (unit & 07);
73925224Smckusick 	modem_status = dmz_addr->octet[octet].octet_rms << 8;
74025224Smckusick 
74125224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
74225224Smckusick 	temp = dmz_addr->octet[octet].octet_lctmr;
74325224Smckusick 	modem_status |= ((temp>>8) & (0x1f));
744*25396Skarels 	line_control = (temp & (0x3f));
74525224Smckusick 
74625224Smckusick 	if (line_control & DMZ_BRK)
74725224Smckusick 		modem_status |= DMZ_BRK;
74825224Smckusick 
74925224Smckusick 	switch (how) {
75025224Smckusick 		case DMSET:
75125224Smckusick 			modem_status = (modem_status & 0xff00) | bits;
75225224Smckusick 			break;
75325224Smckusick 		case DMBIS:
75425224Smckusick 			modem_status |= bits;
75525224Smckusick 			break;
75625224Smckusick 		case DMBIC:
75725224Smckusick 			modem_status &= ~bits;
75825224Smckusick 			break;
75925224Smckusick 		case DMGET:
76025224Smckusick 			(void) splx(priority);
76125224Smckusick 			return (modem_status);
76225224Smckusick 	}
76325224Smckusick 
76425224Smckusick 	if (modem_status & DMZ_BRK)
76525224Smckusick 		line_control |= DMZ_RBK;
76625224Smckusick 	else
76725224Smckusick 		line_control &= ~DMZ_RBK;
76825224Smckusick 	modem_status &= ~DMZ_BRK;
76925224Smckusick 
77025224Smckusick 	dmz_addr->octet[octet].octet_csr =
77125224Smckusick 		DMZ_IE | IR_LCTMR | (unit & 07);
77225224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
77325224Smckusick 		((modem_status & 0x1f) << 8) | (line_control & 0x3f);
77425224Smckusick 
77525224Smckusick 	(void) splx(priority);
77625224Smckusick 	return (modem_status);
77725224Smckusick }
77825224Smckusick 
77925224Smckusick /*
78025224Smckusick  * Routine to convert modem status from dm to dmz format.
78125224Smckusick  * Pull bits 1 & 3 through unchanged. If dm secondary transmit bit is set,
78225224Smckusick  * and/or dm request to send bit is set, and/or dm user modem signal bit
78325224Smckusick  * is set, set the corresponding dmz bits.
78425224Smckusick  */
78525224Smckusick dmtodmz(bits)
78625224Smckusick 	register int bits;
78725224Smckusick {
78825224Smckusick 	register int b;
78925224Smckusick 
79025224Smckusick 	b = bits & 012;
79125224Smckusick 	if (bits & DM_ST)
79225224Smckusick 		b |= DMZ_RAT;
79325224Smckusick 	if (bits & DM_RTS)
79425224Smckusick 		b |= DMZ_RTS;
79525224Smckusick 	if (bits & DM_USR)
79625224Smckusick 		b |= DMZ_USW;
79725224Smckusick 	return (b);
79825224Smckusick }
79925224Smckusick 
80025224Smckusick /*
80125224Smckusick  * Routine to convert modem status from dmz to dm format.  Pull bits 1 & 3
80225224Smckusick  * through unchanged. Pull bits 11 - 15 through as bits 4 - 8 and set bit
80325224Smckusick  * 0 to dm line enable.  If dmz user modem signal bit set, and/or  dmz
80425224Smckusick  * request to send bit set, then set the corresponding dm bit also.
80525224Smckusick  */
80625224Smckusick dmztodm(bits)
80725224Smckusick 	register int bits;
80825224Smckusick {
80925224Smckusick 	register int b;
81025224Smckusick 
81125224Smckusick 	b = (bits & 012) | ((bits >> 7) & 0760) | DM_LE;
81225224Smckusick 	if (bits & DMZ_USR)
81325224Smckusick 		b |= DM_USR;
81425224Smckusick 	if (bits & DMZ_RTS)
81525224Smckusick 		b |= DM_RTS;
81625224Smckusick 	return (b);
81725224Smckusick }
81825224Smckusick #endif
819