xref: /csrg-svn/sys/vax/uba/dmz.c (revision 30322)
125224Smckusick /*
229216Smckusick  * Copyright (c) 1985, 1986 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*30322Skarels  *	@(#)dmz.c	7.2 (Berkeley) 12/19/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 
109*30322Skarels /*
110*30322Skarels  * The clist space is mapped by one terminal driver onto each UNIBUS.
111*30322Skarels  * The identity of the board which allocated resources is recorded,
112*30322Skarels  * so the process may be repeated after UNIBUS resets.
113*30322Skarels  * The UBACVT macro converts a clist space address for unibus uban
114*30322Skarels  * into an i/o space address for the DMA routine.
115*30322Skarels  */
116*30322Skarels int	dmz_uballoc[NUBA];	/* which dmz (if any) allocated unibus map */
117*30322Skarels int	cbase[NUBA];		/* base address of clists in unibus map */
11825224Smckusick #define	UBACVT(x, uban)	    (cbase[uban] + ((x) - (char *)cfree))
11925224Smckusick 
12025224Smckusick /* These flags are for debugging purposes only */
12125224Smckusick int dmz_dma_on = 1;
12225224Smckusick 
12325224Smckusick dmzprobe(reg)
12425224Smckusick 	caddr_t reg;
12525224Smckusick {
12625224Smckusick 	register int br, cvec;
12725224Smckusick 	register struct dmzdevice *dmz_addr;
12825224Smckusick 	register unsigned int a;
12925224Smckusick 
13025224Smckusick 	dmz_addr = (struct dmzdevice *)reg;
13125224Smckusick 
13225224Smckusick #ifdef lint
13325224Smckusick 	br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0);
13425224Smckusick 	dmzrinta(0); dmzrintb(0); dmzrintc(0);
13525224Smckusick #endif
13625224Smckusick 
13725224Smckusick 	br = 0x15;
13825224Smckusick 
13925224Smckusick 	a = dmz_addr->dmz_config;
14025224Smckusick 	if (((a>>12) & ~DMZ_INTERFACE) != 0) {
14125224Smckusick 		printf("	Unknown interface type\n");
14225224Smckusick 		return (0);
14325224Smckusick 	}
14425224Smckusick 	if (((a>>8) & DMZ_NOC_MASK) != 3) {
14525224Smckusick 		printf("	Not all octets are available\n");
14625224Smckusick 		return (0);
14725224Smckusick 	}
14825224Smckusick 
14925224Smckusick 	cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6);
15025224Smckusick 	dmz_addr->dmz_config = cvec >> 2;
15125224Smckusick 
15225224Smckusick 	return (sizeof(struct dmzdevice));
15325224Smckusick }
15425224Smckusick 
15525224Smckusick dmzattach(ui)
15625224Smckusick 	struct uba_device *ui;
15725224Smckusick {
15825224Smckusick 	dmzsoftCAR[ui->ui_unit] = ui->ui_flags;
15926218Skarels 	cbase[ui->ui_ubanum] = -1;
160*30322Skarels 	dmz_uballoc[ui->ui_unit] = -1;
16125224Smckusick }
16225224Smckusick 
16325224Smckusick /* ARGSUSED */
16425224Smckusick dmzopen(device, flag)
16525224Smckusick 	dev_t device;
16625224Smckusick 	int flag;
16725224Smckusick {
16825224Smckusick 	register struct tty *tp;
16925224Smckusick 	register int unit, controller;
17025224Smckusick 	register struct dmzdevice *dmz_addr;
17125224Smckusick 	register struct uba_device *ui;
17225224Smckusick 	int priority;
17325224Smckusick 	int octet;
17425224Smckusick 
17525224Smckusick 	unit = minor(device);
17625224Smckusick 	controller = DMZ(unit);
17725224Smckusick 	octet = OCTET(unit);
17825224Smckusick 
17925224Smckusick 	if (unit >= NDMZLINES ||
18025224Smckusick 	    (ui = dmzinfo[controller]) == 0 ||
18125224Smckusick 	    ui->ui_alive == 0)
18225224Smckusick 		return (ENXIO);
18325224Smckusick 
18425224Smckusick 	tp = &dmz_tty[unit];
18525224Smckusick 
18625224Smckusick 	if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0)
18725224Smckusick 		return (EBUSY);
18825224Smckusick 
18925224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
19025224Smckusick 	tp->t_addr = (caddr_t)dmz_addr;
19125224Smckusick 	tp->t_oproc = dmzstart;
19225224Smckusick 
19325224Smckusick 	/*
19425224Smckusick 	 * Set up Unibus map registers.  Block uba resets, which can
19525224Smckusick 	 * clear the state.
19625224Smckusick 	 */
19725224Smckusick 	priority = spl5();
19826218Skarels 	if (cbase[ui->ui_ubanum] == -1) {
199*30322Skarels 		dmz_uballoc[ui->ui_ubanum] = controller;
200*30322Skarels 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
201*30322Skarels 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
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);
21427051Skarels #ifndef PORTSELECTOR
21527051Skarels 		if (tp->t_ispeed == 0) {
21627051Skarels #else
21727051Skarels 			tp->t_state |= TS_HUPCLS;
21827051Skarels #endif PORTSELECTOR
21927051Skarels 			tp->t_ispeed = ISPEED;
22027051Skarels 			tp->t_ospeed = ISPEED;
22127051Skarels 			tp->t_flags = IFLAGS;
22227051Skarels #ifndef PORTSELECTOR
22327051Skarels 		}
22427051Skarels #endif PORTSELECTOR
22525224Smckusick 		dmz_softc[unit].dmz_state = 0;
22625224Smckusick 	}
22725655Skarels 	dmzparam(unit);
22825224Smckusick 
22925224Smckusick 	/*
23025224Smckusick 	 * Wait for carrier, then process line discipline specific open.
23125224Smckusick 	 */
23225655Skarels 	if ((dmzmctl(unit, DMZ_ON, DMSET) & DMZ_CAR) ||
23325224Smckusick 	    (dmzsoftCAR[controller] & (1 << (unit % 24))))
23425224Smckusick 		tp->t_state |= TS_CARR_ON;
23525224Smckusick 	priority = spl5();
23625224Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
23725224Smckusick 		tp->t_state |= TS_WOPEN;
23825224Smckusick 		sleep((caddr_t) &tp->t_rawq, TTIPRI);
23925224Smckusick 	}
24025224Smckusick 	splx(priority);
24125224Smckusick 
24225435Skarels 	return ((*linesw[tp->t_line].l_open)(device, tp));
24325224Smckusick }
24425224Smckusick 
24525224Smckusick dmzparam(unit)
24625224Smckusick 	register int unit;
24725224Smckusick {
24825224Smckusick 	register struct tty *tp;
24925224Smckusick 	register struct dmzdevice *dmz_addr;
25025655Skarels 	register int line_parameters;
25125224Smckusick 	register int octet;
25225224Smckusick 	int priority;
25325224Smckusick 
25425224Smckusick 	octet = OCTET(unit);
25525224Smckusick 
25625224Smckusick 	tp = &dmz_tty[unit];
25725224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
25825224Smckusick 
25925224Smckusick 	priority = spl5();
26025224Smckusick 	if ((tp->t_ispeed) == 0) {
26125224Smckusick 		tp->t_state |= TS_HUPCLS;
26225224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
26325224Smckusick 		splx(priority);
26425224Smckusick 		return;
26525224Smckusick 	}
26625224Smckusick 
26725224Smckusick 	line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8);
26825224Smckusick 
26925224Smckusick 	if ((tp->t_ispeed) == B134)
27025224Smckusick 		line_parameters |= DMZ_6BT | DMZ_PEN;
27125655Skarels 	else if (tp->t_flags & (RAW | LITOUT | PASS8))
27225224Smckusick 		line_parameters |= DMZ_8BT;
27325224Smckusick 	else
27425224Smckusick 		line_parameters |= DMZ_7BT | DMZ_PEN;
27525224Smckusick 
27625224Smckusick 	if (tp->t_flags & EVENP)
27725224Smckusick 		line_parameters |= DMZ_EPR;
27825224Smckusick 	if ((tp->t_ospeed) == B110)
27925224Smckusick 		line_parameters |= DMZ_SCD;
28025224Smckusick 
28125224Smckusick 	line_parameters |= (unit & 07);
28225224Smckusick 
28325224Smckusick 	dmz_addr->octet[octet].octet_lprm = line_parameters;
28425224Smckusick 	splx(priority);
28525224Smckusick }
28625224Smckusick 
28725224Smckusick /* ARGSUSED */
28825224Smckusick dmzclose(device, flag)
28925224Smckusick 	dev_t device;
29025224Smckusick 	int flag;
29125224Smckusick {
29225224Smckusick 	register struct  tty *tp;
29325224Smckusick 	register int unit;
29425224Smckusick 
29525224Smckusick 	unit = minor(device);
29625224Smckusick 	tp = &dmz_tty[unit];
29725655Skarels 	(*linesw[tp->t_line].l_close)(tp);
29825224Smckusick 
29925224Smckusick 	/*
30025655Skarels 	 * Clear break, hang-up and close the modem.
30125224Smckusick 	 */
30225224Smckusick 	(void) dmzmctl(unit, DMZ_BRK, DMBIC);
30325224Smckusick 	if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
30425224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
30525224Smckusick 	ttyclose(tp);
30625224Smckusick 	return;
30725224Smckusick }
30825224Smckusick 
30925224Smckusick dmzreset(uban)
31025224Smckusick 	int uban;
31125224Smckusick {
31225224Smckusick 	register int controller, unit;
31325224Smckusick 	register struct tty *tp;
31425224Smckusick 	register struct uba_device *ui;
31525224Smckusick 	register struct dmzdevice *dmz_addr;
31625224Smckusick 	int i;
31725224Smckusick 	int octet;
31825224Smckusick 
31925224Smckusick 	for (controller = 0; controller < NDMZ; controller++) {
32025224Smckusick 		ui = dmzinfo[controller];
32125224Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
32225224Smckusick 			continue;
32325224Smckusick 		printf("dmz%d ", controller);
32425224Smckusick 		dmz_addr = (struct dmzdevice *) ui->ui_addr;
32525224Smckusick 
326*30322Skarels 		if (dmz_uballoc[uban] == controller) {
327*30322Skarels 			int info;
328*30322Skarels 
329*30322Skarels 			info = uballoc(uban, (caddr_t)cfree,
330*30322Skarels 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
331*30322Skarels 			if (info)
332*30322Skarels 				cbase[uban] = UBAI_ADDR(info);
333*30322Skarels 			else {
334*30322Skarels 				printf(" [can't get uba map]");
335*30322Skarels 				cbase[uban] = -1;
336*30322Skarels 			}
33725435Skarels 		}
33825435Skarels 
33925224Smckusick 		for (octet = 0; octet < 3; octet++)
34025224Smckusick 			if ((dmzact[controller] & (1 << octet)) != 0) {
34125224Smckusick 				dmz_addr->octet[octet].octet_csr |= DMZ_IE;
34225224Smckusick 				dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
34325224Smckusick 			}
34425224Smckusick 
34525224Smckusick 		unit = controller * 24;
34625224Smckusick 
34725224Smckusick 		/*
34825224Smckusick 		 * If a unit is open or waiting for open to complete,
34925224Smckusick 		 * reset it.
35025224Smckusick 		 */
35125224Smckusick 		for (i = 0; i < 24; i++) {
35225224Smckusick 			dmz_softc[unit].dmz_state = 0;
35325224Smckusick 			tp = &dmz_tty[unit];
35425224Smckusick 			if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) {
35525224Smckusick 				dmzparam(unit);
35625224Smckusick 				(void) dmzmctl(unit, DMZ_ON, DMSET);
35725224Smckusick 				tp->t_state &= ~TS_BUSY;
35825224Smckusick 				dmzstart(tp);
35925224Smckusick 			}
36025224Smckusick 			unit++;
36125224Smckusick 		}
36225224Smckusick 	}
36325224Smckusick 	return;
36425224Smckusick }
36525224Smckusick 
36625224Smckusick dmzread(device, uio)
36725224Smckusick 	dev_t device;
36825224Smckusick 	struct uio *uio;
36925224Smckusick {
37025224Smckusick 	register struct tty *tp;
37125224Smckusick 	int xstatus;
37225224Smckusick 
37325224Smckusick 	tp = &dmz_tty[minor(device)];
37425224Smckusick 	xstatus = (*linesw[tp->t_line].l_read)(tp, uio);
37525224Smckusick 	return (xstatus);
37625224Smckusick }
37725224Smckusick 
37825224Smckusick dmzwrite(device, uio)
37925224Smckusick 	dev_t device;
38025224Smckusick 	struct uio *uio;
38125224Smckusick {
38225224Smckusick 	register struct tty *tp;
38325224Smckusick 	int xstatus;
38425224Smckusick 
38525224Smckusick 	tp = &dmz_tty[minor(device)];
38625224Smckusick 	xstatus = (*linesw[tp->t_line].l_write)(tp, uio);
38725224Smckusick 	return (xstatus);
38825224Smckusick }
38925224Smckusick 
39025224Smckusick dmzrinta(controller)
39125224Smckusick 	int controller;
39225224Smckusick {
39325224Smckusick 	dmzrint(controller, 0);
39425224Smckusick }
39525224Smckusick 
39625224Smckusick dmzrintb(controller)
39725224Smckusick 	int controller;
39825224Smckusick {
39925224Smckusick 	dmzrint(controller, 1);
40025224Smckusick }
40125224Smckusick 
40225224Smckusick dmzrintc(controller)
40325224Smckusick 	int controller;
40425224Smckusick {
40525224Smckusick 	dmzrint(controller, 2);
40625224Smckusick }
40725224Smckusick 
40825224Smckusick dmzrint(controller, octet)
40925224Smckusick 	int controller;
41025224Smckusick 	register int octet;
41125224Smckusick {
41225224Smckusick 	register struct tty *tp;
41325224Smckusick 	register int character;
41425224Smckusick 	register struct dmzdevice *dmz_addr;
41525224Smckusick 	register struct tty *tp0;
41625224Smckusick 	register int unit;
41725224Smckusick 	register struct uba_device *ui;
41825396Skarels 	int overrun;
41925224Smckusick 
42025224Smckusick 	overrun = 0;
42125224Smckusick 	ui = dmzinfo[controller];
42225224Smckusick 	if (ui == 0 || ui->ui_alive == 0)
42325224Smckusick 		return;
42425224Smckusick 	dmz_addr = (struct dmzdevice *) ui->ui_addr;
42525224Smckusick 	tp0 = &dmz_tty[controller * 24];
42625224Smckusick 
42725224Smckusick 	while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) {
42825224Smckusick 		unit = (character >> 8) & 07;	/* unit is bits 8-10 of rb */
42925224Smckusick 		tp = tp0 + (octet * 8 + unit);
43025224Smckusick 
43126218Skarels 		if (character & DMZ_DSC) {
43225655Skarels 			dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | unit;
43325655Skarels 			if (dmz_addr->octet[octet].octet_rmstsc & DMZ_CAR)
43425396Skarels 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
43527051Skarels 			else if ((dmzsoftCAR[controller] &
43627051Skarels 			    (1 << (octet * 8 + unit))) == 0 &&
43726218Skarels 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
43825655Skarels 				(void)dmzmctl(tp - dmz_tty, DMZ_OFF, DMSET);
43925224Smckusick 			continue;
44025224Smckusick 		}
44125224Smckusick 
44225396Skarels 		if ((tp->t_state&TS_ISOPEN)==0) {
44325396Skarels 			wakeup((caddr_t)&tp->t_rawq);
44425396Skarels #ifdef PORTSELECTOR
44525396Skarels 			if ((tp->t_state&TS_WOPEN) == 0)
44625396Skarels #endif
44725396Skarels 				continue;
44825224Smckusick 		}
44925224Smckusick 
45025224Smckusick 		if (character & DMZ_PE) {
45125224Smckusick 			if ((tp->t_flags & (EVENP | ODDP)) == EVENP ||
45225224Smckusick 			    (tp->t_flags & (EVENP | ODDP)) == ODDP)
45325224Smckusick 				continue;
45425224Smckusick 		}
45525224Smckusick 
45625224Smckusick 		if ((character & DMZ_DO) && overrun == 0) {
45725435Skarels 			log(LOG_WARNING, "dmz%d: silo overflow\n", controller);
45825224Smckusick 			overrun = 1;
45925224Smckusick 		}
46025224Smckusick 
46125224Smckusick 		if (character & DMZ_FE) {
46225224Smckusick 			if (tp->t_flags & RAW)
46325224Smckusick 				character = 0;
46425224Smckusick 			else
46525224Smckusick 				character = tp->t_intrc;
46625224Smckusick 		}
46725224Smckusick 
46825224Smckusick 		(*linesw[tp->t_line].l_rint)(character, tp);
46925224Smckusick 	}
47025224Smckusick 
47125224Smckusick 	return;
47225224Smckusick }
47325224Smckusick 
47425224Smckusick dmzxinta(controller)
47525224Smckusick 	int controller;
47625224Smckusick {
47725224Smckusick 	dmzxint(controller, 0);
47825224Smckusick }
47925224Smckusick 
48025224Smckusick dmzxintb(controller)
48125224Smckusick 	int controller;
48225224Smckusick {
48325224Smckusick 	dmzxint(controller, 1);
48425224Smckusick }
48525224Smckusick 
48625224Smckusick dmzxintc(controller)
48725224Smckusick 	int controller;
48825224Smckusick {
48925224Smckusick 	dmzxint(controller, 2);
49025224Smckusick }
49125224Smckusick 
49225224Smckusick dmzxint(controller, octet)
49325224Smckusick 	int controller;
49425224Smckusick 	register int octet;
49525224Smckusick {
49625224Smckusick 	register struct tty *tp;
49725224Smckusick 	register struct dmzdevice *dmz_addr;
49825224Smckusick 	register struct uba_device *ui;
49925224Smckusick 	register int unit, t;
50025224Smckusick 	int priority;
50125224Smckusick 
50225224Smckusick 	ui = dmzinfo[controller];
50325224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
50425224Smckusick 
50525224Smckusick 	priority = spl5();
50625224Smckusick 
50725224Smckusick 	while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) {
50825224Smckusick 		unit = controller * 24 + (octet * 8 + ((t>>8) & 07));
50925224Smckusick 		tp = &dmz_tty[unit];
51025224Smckusick 		tp->t_state &= ~TS_BUSY;
51125224Smckusick 
51225224Smckusick 		if (t & DMZ_NXM)
51325224Smckusick 			printf("dmz%d: NXM line %d\n", controller,
51425224Smckusick 				octet * 8 + (unit & 07));
51525224Smckusick 
51625224Smckusick 		if (tp->t_state & TS_FLUSH) {
51725224Smckusick 			tp->t_state &= ~TS_FLUSH;
51825224Smckusick 			dmz_addr->octet[octet].octet_csr =
51925224Smckusick 				DMZ_IE | IR_LCTMR | (unit & 07);
52025224Smckusick 			dmz_addr->octet[octet].octet_lctmr =
52125224Smckusick 				(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
52225224Smckusick 		} else
52325224Smckusick 			if (dmz_softc[unit].dmz_state & ST_DMA)
52425224Smckusick 				ndflush(&tp->t_outq, dmz_softc[unit].dmz_count);
52525224Smckusick 		dmz_softc[unit].dmz_state = 0;
52625224Smckusick 
52725224Smckusick 		if (tp->t_line)
52825224Smckusick 			(*linesw[tp->t_line].l_start)(tp);
52925224Smckusick 		else
53025224Smckusick 			dmzstart(tp);
53125224Smckusick 	}
53225224Smckusick 
53325224Smckusick 	splx(priority);
53425224Smckusick 	return;
53525224Smckusick }
53625224Smckusick 
53725224Smckusick dmzstart(tp)
53825224Smckusick 	register struct tty *tp;
53925224Smckusick {
54025224Smckusick 	register struct dmzdevice *dmz_addr;
54125224Smckusick 	register int unit, nch, room;
54225224Smckusick 	int controller, octet;
54325224Smckusick 	int priority, car, use_dma;
54425224Smckusick 	register int i;
54525224Smckusick 	register char *cp;
54625224Smckusick 
54725224Smckusick 	unit = minor(tp->t_dev);
54825224Smckusick 	controller = DMZ(unit);
54925224Smckusick 	octet = OCTET(unit);
55025224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
55125224Smckusick 
55225224Smckusick 	priority = spl5();
55325224Smckusick 
55425224Smckusick 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
55525224Smckusick 		goto out;
55625224Smckusick 
55725224Smckusick 	/*
55825224Smckusick 	 * If the transmitter has been disabled, reenable it.
55925224Smckusick 	 * If the transmitter was disabled before the xint (the
56025224Smckusick 	 * ST_INBUSY was still on), then reset the BUSY state and
56125224Smckusick 	 * we will wait for the interrupt.  If !TS_BUSY, we already
56225224Smckusick 	 * saw the interrupt so we can start another transmission.
56325224Smckusick 	 */
56425224Smckusick 	if (dmz_softc[unit].dmz_state & ST_TXOFF) {
56525224Smckusick 		dmz_addr->octet[octet].octet_csr =
56625224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
56725224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
56825224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
56925224Smckusick 		dmz_softc[unit].dmz_state &= ~ST_TXOFF;
57025224Smckusick 		if (dmz_softc[unit].dmz_state & ST_INBUSY) {
57125224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_INBUSY;
57225224Smckusick 			tp->t_state |= TS_BUSY;
57325224Smckusick 			goto out;
57425224Smckusick 		}
57525224Smckusick 	}
57625224Smckusick 
57725224Smckusick 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
57825224Smckusick 		if (tp->t_state & TS_ASLEEP) {
57925224Smckusick 			tp->t_state &= ~TS_ASLEEP;
58025224Smckusick 			wakeup((caddr_t)&tp->t_outq);
58125224Smckusick 		}
58225224Smckusick 		if (tp->t_wsel) {
58325224Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
58425224Smckusick 			tp->t_wsel = 0;
58525224Smckusick 			tp->t_state &= ~TS_WCOLL;
58625224Smckusick 		}
58725224Smckusick 	}
58825224Smckusick 
58925224Smckusick 	if (tp->t_outq.c_cc == 0)
59025224Smckusick 		goto out;
59127443Slepreau 	if (tp->t_flags & (RAW | LITOUT))
59225224Smckusick 		nch = ndqb(&tp->t_outq, 0);
59325224Smckusick 	else {
59425224Smckusick 		nch = ndqb(&tp->t_outq, 0200);
59525224Smckusick 		if (nch == 0) {
59625224Smckusick 			nch = getc(&tp->t_outq);
59725224Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6);
59825224Smckusick 			tp->t_state |= TS_TIMEOUT;
59925224Smckusick 			goto out;
60025224Smckusick 		}
60125224Smckusick 	}
60225224Smckusick 
60325224Smckusick 	/*
60425224Smckusick 	 * Should we use DMA or SILO mode?
60525224Smckusick 	 * If nch is greater than DO_DMA_COUNT then DMA.
60625224Smckusick 	 */
60725224Smckusick 	if (nch) {
60825224Smckusick 		dmz_addr->octet[octet].octet_csr =
60925224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
61025224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
61125224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
61225224Smckusick 		tp->t_state |= TS_BUSY;
61325224Smckusick 
61425224Smckusick 		use_dma = FALSE;
61525224Smckusick 		room = DMZ_SIZ;
61625224Smckusick 
61725224Smckusick 		if (nch > DO_DMA_COUNT)
61825224Smckusick 			use_dma = TRUE;
61925224Smckusick 
62025224Smckusick 		if (use_dma && dmz_dma_on) {
62125224Smckusick 			car = UBACVT(tp->t_outq.c_cf,
62225224Smckusick 				dmzinfo[controller]->ui_ubanum);
62325224Smckusick 			dmz_softc[unit].dmz_count = nch;
62425224Smckusick 			dmz_softc[unit].dmz_state |= ST_DMA;
62525224Smckusick 			dmz_addr->octet[octet].octet_csr =
62625224Smckusick 				DMZ_IE | IR_TBA | (unit & 07);
62725224Smckusick 			dmz_addr->octet[octet].octet_tba = car;
62825224Smckusick 			dmz_addr->octet[octet].octet_tcc =
62925224Smckusick 				((car >> 2) & 0xc000) | nch;
63025224Smckusick 		} else {
63125224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_DMA;
63225224Smckusick 			cp = tp->t_outq.c_cf;
63325224Smckusick 			nch = MIN(nch, room);
63425224Smckusick 			dmz_addr->octet[octet].octet_csr =
63525224Smckusick 				DMZ_IE | IR_TBUF | (unit & 07);
63625224Smckusick 			for (i = 0; i < nch; i++)
63725224Smckusick 				dmz_addr->octet[octet].octet_tbf = *cp++ ;
63825224Smckusick 			ndflush(&tp->t_outq, nch);
63925224Smckusick 		}
64025224Smckusick 	}
64125224Smckusick 
64225224Smckusick out:
64325224Smckusick 	splx(priority);
64425224Smckusick 	return;
64525224Smckusick }
64625224Smckusick 
64725224Smckusick /* ARGSUSED */
64825224Smckusick dmzstop(tp, flag)
64925224Smckusick 	register struct tty *tp;
65025224Smckusick {
65125224Smckusick 	register struct dmzdevice *dmz_addr;
65225224Smckusick 	register int unit, priority, octet;
65325224Smckusick 
65425224Smckusick 	priority = spl5();
65525224Smckusick 	dmz_addr = (struct dmzdevice *) tp->t_addr;
65625224Smckusick 	unit = minor(tp->t_dev);
65725224Smckusick 	octet = OCTET(unit);
65825224Smckusick 
65925224Smckusick 	dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE;
66025224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
66125224Smckusick 		(dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE);
66225224Smckusick 	dmz_softc[unit].dmz_state |= ST_TXOFF;
66325224Smckusick 	if ((tp->t_state & TS_TTSTOP) == 0) {
66425224Smckusick 		tp->t_state |= (TS_FLUSH | TS_BUSY);
66525224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
66625224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_FLS);
66725224Smckusick 	} else if (tp->t_state & TS_BUSY) {
66825224Smckusick 		dmz_softc[unit].dmz_state |= ST_INBUSY;
66925224Smckusick 		tp->t_state &= ~TS_BUSY;
67025224Smckusick 	}
67125224Smckusick 
67225224Smckusick 	splx(priority);
67325224Smckusick 	return;
67425224Smckusick }
67525224Smckusick 
67625224Smckusick /* ARGSUSED */
67725224Smckusick dmzioctl(device, command, data, flag)
67825224Smckusick 	dev_t device;
67925224Smckusick 	caddr_t data;
68025224Smckusick {
68125224Smckusick 	register struct tty *tp;
68225224Smckusick 	register int unit;
68325224Smckusick 	int error;
68425224Smckusick 
68525224Smckusick 	unit = minor(device);
68625224Smckusick 	tp = &dmz_tty[unit];
68725224Smckusick 
68825224Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag);
68925224Smckusick 	if (error >= 0)
69025224Smckusick 		return (error);
69125224Smckusick 	error = ttioctl(tp, command, data, flag);
69225224Smckusick 	if (error >= 0) {
69325655Skarels 		if (command == TIOCSETP || command == TIOCSETN ||
69425655Skarels 		    command == TIOCLSET || command == TIOCLBIS ||
69525655Skarels 		    command == TIOCLBIC)
69625224Smckusick 			dmzparam(unit);
69725224Smckusick 		return (error);
69825224Smckusick 	}
69925224Smckusick 
70025224Smckusick 	switch (command) {
70125224Smckusick 		case TIOCSBRK:
70225655Skarels 			(void) dmzmctl(unit, DMZ_BRK, DMBIS);
70325224Smckusick 			break;
70425224Smckusick 		case TIOCCBRK:
70525655Skarels 			(void) dmzmctl(unit, DMZ_BRK, DMBIC);
70625224Smckusick 			break;
70725224Smckusick 		case TIOCSDTR:
70825655Skarels 			(void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIS);
70925224Smckusick 			break;
71025224Smckusick 		case TIOCCDTR:
71125655Skarels 			(void) dmzmctl(unit, DMZ_DTR | DMZ_RTS, DMBIC);
71225224Smckusick 			break;
71325224Smckusick 		case TIOCMSET:
71425655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMSET);
71525224Smckusick 			break;
71625224Smckusick 		case TIOCMBIS:
71725655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIS);
71825224Smckusick 			break;
71925224Smckusick 		case TIOCMBIC:
72025655Skarels 			(void) dmzmctl(unit, dmtodmz(*(int *)data), DMBIC);
72125224Smckusick 			break;
72225224Smckusick 		case TIOCMGET:
72325655Skarels 			*(int *)data = dmzmctl(unit, 0, DMGET);
72425224Smckusick 			break;
72525224Smckusick 		default:
72625224Smckusick 			return (ENOTTY);
72725224Smckusick 	}
72825224Smckusick 	return (0);
72925224Smckusick }
73025224Smckusick 
73125655Skarels dmzmctl(unit, bits, how)
73225655Skarels 	register int unit;
73325224Smckusick 	int bits, how;
73425224Smckusick {
73525224Smckusick 	register struct dmzdevice *dmz_addr;
73625655Skarels 	register int modem_status, line_control;
73725224Smckusick 	int priority;
73825224Smckusick 	int octet;
73925224Smckusick 
74025224Smckusick 	octet = OCTET(unit);
74125655Skarels 	dmz_addr = (struct dmzdevice *) dmzinfo[DMZ(unit)]->ui_addr;
74225224Smckusick 
74325224Smckusick 	priority = spl5();
74425655Skarels 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMSTSC | (unit & 07);
74525655Skarels 	modem_status = dmz_addr->octet[octet].octet_rmstsc & 0xff00;
74625224Smckusick 
74725224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
74825655Skarels 	line_control = dmz_addr->octet[octet].octet_lctmr;
74925224Smckusick 
75025224Smckusick 
75125224Smckusick 	switch (how) {
75225224Smckusick 		case DMSET:
75325655Skarels 			line_control = bits;
75425224Smckusick 			break;
75525224Smckusick 		case DMBIS:
75625655Skarels 			line_control |= bits;
75725224Smckusick 			break;
75825224Smckusick 		case DMBIC:
75925655Skarels 			line_control &= ~bits;
76025224Smckusick 			break;
76125224Smckusick 		case DMGET:
76225224Smckusick 			(void) splx(priority);
76325655Skarels 			return (dmztodm(modem_status, line_control));
76425224Smckusick 	}
76525224Smckusick 
76625224Smckusick 	dmz_addr->octet[octet].octet_csr =
76725224Smckusick 		DMZ_IE | IR_LCTMR | (unit & 07);
76825655Skarels 	dmz_addr->octet[octet].octet_lctmr = line_control;
76925224Smckusick 
77025655Skarels 	splx(priority);
77125224Smckusick 	return (modem_status);
77225224Smckusick }
77325224Smckusick 
77425224Smckusick /*
77525655Skarels  * Routine to convert modem status from dm to dmz lctmr format.
77625224Smckusick  */
77725224Smckusick dmtodmz(bits)
77825224Smckusick 	register int bits;
77925224Smckusick {
78025655Skarels 	register int lcr = DMZ_LCE;
78125224Smckusick 
78225655Skarels 	if (bits & DML_DTR)
78325655Skarels 		lcr |= DMZ_DTR;
78425655Skarels 	if (bits & DML_RTS)
78525655Skarels 		lcr |= DMZ_RTS;
78625655Skarels 	if (bits & DML_ST)
78725655Skarels 		lcr |= DMF_ST;
78825655Skarels 	if (bits & DML_USR)
78925655Skarels 		lcr |= DMZ_USRW;
79025655Skarels 	return (lcr);
79125224Smckusick }
79225224Smckusick 
79325224Smckusick /*
79425655Skarels  * Routine to convert modem status from dmz receive modem status
79525655Skarels  * and line control register to dm format.
79625655Skarels  * If dmz user modem read bit set, set DML_USR.
79725224Smckusick  */
79825655Skarels dmztodm(rms, lcr)
79925655Skarels 	register int rms, lcr;
80025224Smckusick {
80125224Smckusick 
80225655Skarels 	rms = ((rms & (DMZ_DSR|DMZ_RNG|DMZ_CAR|DMZ_CTS|DMF_SR)) >> 7) |
80325655Skarels 		((rms & DMZ_USRR) >> 1) | DML_LE;
80425655Skarels 	if (lcr & DMZ_DTR)
80525655Skarels 		rms |= DML_DTR;
80625655Skarels 	if (lcr & DMF_ST)
80725655Skarels 		rms |= DML_ST;
80825655Skarels 	if (lcr & DMZ_RTS)
80925655Skarels 		rms |= DML_RTS;
81025655Skarels 	return (rms);
81125224Smckusick }
81225224Smckusick #endif
813