xref: /csrg-svn/sys/vax/uba/dmz.c (revision 25224)
1*25224Smckusick /*
2*25224Smckusick  * Copyright (c) 1985 Regents of the University of California.
3*25224Smckusick  * All rights reserved.  The Berkeley software License Agreement
4*25224Smckusick  * specifies the terms and conditions for redistribution.
5*25224Smckusick  *
6*25224Smckusick  *	@(#)dmz.c	6.1 (Berkeley) 10/17/85
7*25224Smckusick  */
8*25224Smckusick 
9*25224Smckusick /*
10*25224Smckusick  * DMZ-32 driver
11*25224Smckusick  * HISTORY
12*25224Smckusick  * 23-Apr-85  Joe Camaratta (jcc) at Siemens RTL
13*25224Smckusick  *	Driver for DEC's DMZ32 24-line asynchronous multiplexor.
14*25224Smckusick  *	Based on Chris Maloney's driver for DEC's DMF32
15*25224Smckusick  *	NOTE: The modem control routines have NOT been tested yet!!!
16*25224Smckusick  *
17*25224Smckusick  * 9-Aug-85	Mike Meyer (mwm) at ucb
18*25224Smckusick  *	Mangled into shape for 4.3.
19*25224Smckusick  */
20*25224Smckusick 
21*25224Smckusick #include "dmz.h"
22*25224Smckusick #if NDMZ > 0
23*25224Smckusick 
24*25224Smckusick 
25*25224Smckusick #include "../machine/pte.h"
26*25224Smckusick 
27*25224Smckusick 
28*25224Smckusick #include "bk.h"
29*25224Smckusick #include "uba.h"
30*25224Smckusick #include "param.h"
31*25224Smckusick #include "conf.h"
32*25224Smckusick #include "dir.h"
33*25224Smckusick #include "user.h"
34*25224Smckusick #include "ioctl.h"
35*25224Smckusick #include "tty.h"
36*25224Smckusick #include "map.h"
37*25224Smckusick #include "buf.h"
38*25224Smckusick #include "vm.h"
39*25224Smckusick #include "bkmac.h"
40*25224Smckusick #include "clist.h"
41*25224Smckusick #include "file.h"
42*25224Smckusick #include "uio.h"
43*25224Smckusick #include "kernel.h"
44*25224Smckusick 
45*25224Smckusick #include "ubareg.h"
46*25224Smckusick #include "ubavar.h"
47*25224Smckusick #include "dmzreg.h"
48*25224Smckusick 
49*25224Smckusick int dmzprobe(), dmzattach(), dmzrint(), dmzxint();
50*25224Smckusick struct uba_device *dmzinfo[NDMZ];
51*25224Smckusick u_short dmzstd[] = {0, 0};
52*25224Smckusick struct uba_driver dmzdriver = {
53*25224Smckusick 	dmzprobe, 0, dmzattach, 0, dmzstd, "dmz", dmzinfo
54*25224Smckusick };
55*25224Smckusick 
56*25224Smckusick #define	NDMZLINES	(NDMZ*24)
57*25224Smckusick 
58*25224Smckusick int ttrstrt();
59*25224Smckusick struct tty dmz_tty[NDMZLINES];
60*25224Smckusick 
61*25224Smckusick int dmzsoftCAR[NDMZ];
62*25224Smckusick 
63*25224Smckusick struct {
64*25224Smckusick 	char dmz_state;		/* dmz state */
65*25224Smckusick 	int dmz_count;		/* dmz dma count */
66*25224Smckusick } dmz_softc[NDMZ*24];
67*25224Smckusick 
68*25224Smckusick #define	ST_TXOFF	(0x01)	/* transmission turned off (^S) */
69*25224Smckusick #define	ST_DMA		(0x02)	/* dma inprogress */
70*25224Smckusick #define	ST_INBUSY	(0x04)	/* stop transmission in busy */
71*25224Smckusick 
72*25224Smckusick char dmz_speeds[] = {
73*25224Smckusick 	0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0
74*25224Smckusick };
75*25224Smckusick 
76*25224Smckusick #ifndef lint
77*25224Smckusick int ndmz = NDMZLINES;		/* Used by pstat/iostat */
78*25224Smckusick #endif
79*25224Smckusick 
80*25224Smckusick short dmzact[NDMZ];		/* Mask of active octets on the dmz */
81*25224Smckusick int dmzstart();
82*25224Smckusick 
83*25224Smckusick /*
84*25224Smckusick  * SILO_TIMEOUT represents the number of milliseconds characters can sit
85*25224Smckusick  * in the input silo without causing an interrupt.  If data overruns or
86*25224Smckusick  * slow XON/XOFF occur, set it lower but AT LEAST equal to 1.
87*25224Smckusick  */
88*25224Smckusick #define	SILO_TIMEOUT	(3)
89*25224Smckusick 
90*25224Smckusick /*
91*25224Smckusick  * DO_DMA_COUNT represents the threshold of the number of output
92*25224Smckusick  * characters beyond which the driver uses DMA mode.
93*25224Smckusick  */
94*25224Smckusick #define	DO_DMA_COUNT	(10)
95*25224Smckusick 
96*25224Smckusick #define	TRUE		(1)
97*25224Smckusick #define	FALSE		(0)
98*25224Smckusick 
99*25224Smckusick static int cbase[NUBA];		/* base address in unibus map */
100*25224Smckusick int dmz_ubinfo[NUBA];		/* info about allocated unibus map */
101*25224Smckusick 
102*25224Smckusick #define	UBACVT(x, uban)	    (cbase[uban] + ((x) - (char *)cfree))
103*25224Smckusick 
104*25224Smckusick /* These flags are for debugging purposes only */
105*25224Smckusick int dmz_dma_on = 1;
106*25224Smckusick int dmz_debug_level;
107*25224Smckusick 
108*25224Smckusick dmzprobe(reg)
109*25224Smckusick 	caddr_t reg;
110*25224Smckusick {
111*25224Smckusick 	register int br, cvec;
112*25224Smckusick 	register struct dmzdevice *dmz_addr;
113*25224Smckusick 	register unsigned int a;
114*25224Smckusick 
115*25224Smckusick 	dmz_addr = (struct dmzdevice *)reg;
116*25224Smckusick 
117*25224Smckusick #ifdef lint
118*25224Smckusick 	br = 0; cvec = br; br = cvec; dmzxinta(0); dmzxintb(0); dmzxintc(0);
119*25224Smckusick 	dmzrinta(0); dmzrintb(0); dmzrintc(0);
120*25224Smckusick #endif
121*25224Smckusick 
122*25224Smckusick 	br = 0x15;
123*25224Smckusick 
124*25224Smckusick 	a = dmz_addr->dmz_config;
125*25224Smckusick 	if (((a>>12) & ~DMZ_INTERFACE) != 0) {
126*25224Smckusick 		printf("	Unknown interface type\n");
127*25224Smckusick 		return (0);
128*25224Smckusick 	}
129*25224Smckusick 	if (((a>>8) & DMZ_NOC_MASK) != 3) {
130*25224Smckusick 		printf("	Not all octets are available\n");
131*25224Smckusick 		return (0);
132*25224Smckusick 	}
133*25224Smckusick 
134*25224Smckusick 	cvec = (uba_hd[numuba].uh_lastiv -= 4 * 6);
135*25224Smckusick 	dmz_addr->dmz_config = cvec >> 2;
136*25224Smckusick 
137*25224Smckusick 	return (sizeof(struct dmzdevice));
138*25224Smckusick }
139*25224Smckusick 
140*25224Smckusick dmzattach(ui)
141*25224Smckusick 	struct uba_device *ui;
142*25224Smckusick {
143*25224Smckusick 	dmzsoftCAR[ui->ui_unit] = ui->ui_flags;
144*25224Smckusick 	return;
145*25224Smckusick }
146*25224Smckusick 
147*25224Smckusick /* ARGSUSED */
148*25224Smckusick dmzopen(device, flag)
149*25224Smckusick 	dev_t device;
150*25224Smckusick 	int flag;
151*25224Smckusick {
152*25224Smckusick 	register struct tty *tp;
153*25224Smckusick 	register int unit, controller;
154*25224Smckusick 	register struct dmzdevice *dmz_addr;
155*25224Smckusick 	register struct uba_device *ui;
156*25224Smckusick 	int priority;
157*25224Smckusick 	int xstatus;
158*25224Smckusick 	int octet;
159*25224Smckusick 
160*25224Smckusick 	unit = minor(device);
161*25224Smckusick 	controller = DMZ(unit);
162*25224Smckusick 	octet = OCTET(unit);
163*25224Smckusick 
164*25224Smckusick 	if (unit >= NDMZLINES ||
165*25224Smckusick 	    (ui = dmzinfo[controller]) == 0 ||
166*25224Smckusick 	    ui->ui_alive == 0)
167*25224Smckusick 		return (ENXIO);
168*25224Smckusick 
169*25224Smckusick 	tp = &dmz_tty[unit];
170*25224Smckusick 
171*25224Smckusick 	if ((tp->t_state & TS_XCLUDE) && u.u_uid != 0)
172*25224Smckusick 		return (EBUSY);
173*25224Smckusick 
174*25224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
175*25224Smckusick 	tp->t_addr = (caddr_t)dmz_addr;
176*25224Smckusick 	tp->t_oproc = dmzstart;
177*25224Smckusick 	tp->t_state |= TS_WOPEN;
178*25224Smckusick 
179*25224Smckusick 	/*
180*25224Smckusick 	 * Set up Unibus map registers.  Block uba resets, which can
181*25224Smckusick 	 * clear the state.
182*25224Smckusick 	 */
183*25224Smckusick 	priority = spl5();
184*25224Smckusick 	if (dmz_ubinfo[ui->ui_ubanum] == 0) {
185*25224Smckusick 		dmz_ubinfo[ui->ui_ubanum] =
186*25224Smckusick 			uballoc(ui->ui_ubanum, (caddr_t)cfree,
187*25224Smckusick 				nclist * sizeof(struct cblock), 0);
188*25224Smckusick 		if (dmz_ubinfo[ui->ui_ubanum] == 0) {
189*25224Smckusick 			splx(priority);
190*25224Smckusick 			printf("dmz: insufficient unibus map regs\n");
191*25224Smckusick 			return (-1); /* Is this the right thing to return? */
192*25224Smckusick 		}
193*25224Smckusick 		cbase[ui->ui_ubanum] = dmz_ubinfo[ui->ui_ubanum] & 0x3ffff;
194*25224Smckusick 	}
195*25224Smckusick 
196*25224Smckusick 	if ((dmzact[controller] & (1 << octet)) == 0) {
197*25224Smckusick 		dmz_addr->octet[octet].octet_csr |= DMZ_IE;
198*25224Smckusick 		dmzact[controller] |= 1 << octet;
199*25224Smckusick 		dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
200*25224Smckusick 	}
201*25224Smckusick 
202*25224Smckusick 	splx(priority);
203*25224Smckusick 
204*25224Smckusick 	if ((tp->t_state & TS_ISOPEN) == 0) {
205*25224Smckusick 		ttychars(tp);
206*25224Smckusick 		if (tp->t_ispeed == 0) {
207*25224Smckusick 			tp->t_ispeed = tp->t_ospeed = B300;
208*25224Smckusick 			tp->t_flags = ODDP | EVENP | ECHO;
209*25224Smckusick 		}
210*25224Smckusick 		dmzparam(unit);
211*25224Smckusick 		dmz_softc[unit].dmz_state = 0;
212*25224Smckusick 	}
213*25224Smckusick 
214*25224Smckusick 	/*
215*25224Smckusick 	 * Wait for carrier, then process line discipline specific open.
216*25224Smckusick 	 */
217*25224Smckusick 	if ((dmzmctl(device, DMZ_ON, DMSET) & (DMZ_CAR << 8)) ||
218*25224Smckusick 	    (dmzsoftCAR[controller] & (1 << (unit % 24))))
219*25224Smckusick 		tp->t_state |= TS_CARR_ON;
220*25224Smckusick 	priority = spl5();
221*25224Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
222*25224Smckusick 		tp->t_state |= TS_WOPEN;
223*25224Smckusick 		sleep((caddr_t) &tp->t_rawq, TTIPRI);
224*25224Smckusick 	}
225*25224Smckusick 	splx(priority);
226*25224Smckusick 
227*25224Smckusick 	xstatus = (*linesw[tp->t_line].l_open)(device, tp);
228*25224Smckusick 	return (xstatus);
229*25224Smckusick }
230*25224Smckusick 
231*25224Smckusick dmzparam(unit)
232*25224Smckusick 	register int unit;
233*25224Smckusick {
234*25224Smckusick 	register struct tty *tp;
235*25224Smckusick 	register struct dmzdevice *dmz_addr;
236*25224Smckusick 	register int line_parameters, line_control;
237*25224Smckusick 	register int octet;
238*25224Smckusick 	int priority;
239*25224Smckusick 
240*25224Smckusick 	octet = OCTET(unit);
241*25224Smckusick 
242*25224Smckusick 	tp = &dmz_tty[unit];
243*25224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
244*25224Smckusick 
245*25224Smckusick 	priority = spl5();
246*25224Smckusick 	if ((tp->t_ispeed) == 0) {
247*25224Smckusick 		tp->t_state |= TS_HUPCLS;
248*25224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
249*25224Smckusick 		splx(priority);
250*25224Smckusick 		return;
251*25224Smckusick 	}
252*25224Smckusick 
253*25224Smckusick 	line_parameters = (dmz_speeds[tp->t_ospeed] << 12) | (dmz_speeds[tp->t_ispeed] << 8);
254*25224Smckusick 	line_control = DMZ_LCE;
255*25224Smckusick 
256*25224Smckusick 	if ((tp->t_ispeed) == B134)
257*25224Smckusick 		line_parameters |= DMZ_6BT | DMZ_PEN;
258*25224Smckusick 	else if (tp->t_flags & (RAW | LITOUT))
259*25224Smckusick 		line_parameters |= DMZ_8BT;
260*25224Smckusick 	else
261*25224Smckusick 		line_parameters |= DMZ_7BT | DMZ_PEN;
262*25224Smckusick 
263*25224Smckusick 	if (tp->t_flags & EVENP)
264*25224Smckusick 		line_parameters |= DMZ_EPR;
265*25224Smckusick 	if ((tp->t_ospeed) == B110)
266*25224Smckusick 		line_parameters |= DMZ_SCD;
267*25224Smckusick 
268*25224Smckusick 	line_parameters |= (unit & 07);
269*25224Smckusick 
270*25224Smckusick 	dmz_addr->octet[octet].octet_lprm = line_parameters;
271*25224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
272*25224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
273*25224Smckusick 	    (dmz_addr->octet[octet].octet_lctmr | (line_control & 0xff));
274*25224Smckusick 
275*25224Smckusick 	splx(priority);
276*25224Smckusick 	return;
277*25224Smckusick }
278*25224Smckusick 
279*25224Smckusick /* ARGSUSED */
280*25224Smckusick dmzclose(device, flag)
281*25224Smckusick 	dev_t device;
282*25224Smckusick 	int flag;
283*25224Smckusick {
284*25224Smckusick 	register struct  tty *tp;
285*25224Smckusick 	register int unit;
286*25224Smckusick 
287*25224Smckusick 	unit = minor(device);
288*25224Smckusick 	tp = &dmz_tty[unit];
289*25224Smckusick 
290*25224Smckusick 	/*
291*25224Smckusick 	 * Break, hang-up and close the modem.
292*25224Smckusick 	 */
293*25224Smckusick 	(void) dmzmctl(unit, DMZ_BRK, DMBIC);
294*25224Smckusick 	if (tp->t_state & TS_HUPCLS || (tp->t_state & TS_ISOPEN) == 0)
295*25224Smckusick 		(void) dmzmctl(unit, DMZ_OFF, DMSET);
296*25224Smckusick 	ttyclose(tp);
297*25224Smckusick 	return;
298*25224Smckusick }
299*25224Smckusick 
300*25224Smckusick dmzreset(uban)
301*25224Smckusick 	int uban;
302*25224Smckusick {
303*25224Smckusick 	register int controller, unit;
304*25224Smckusick 	register struct tty *tp;
305*25224Smckusick 	register struct uba_device *ui;
306*25224Smckusick 	register struct dmzdevice *dmz_addr;
307*25224Smckusick 	int i;
308*25224Smckusick 	int octet;
309*25224Smckusick 
310*25224Smckusick 	if (dmz_ubinfo[uban] == 0)
311*25224Smckusick 		return;
312*25224Smckusick 
313*25224Smckusick 	dmz_ubinfo[uban] = uballoc(uban, (caddr_t) cfree, nclist * sizeof(struct cblock), 0);
314*25224Smckusick 	cbase[uban] = dmz_ubinfo[uban] & 0x3ffff;
315*25224Smckusick 
316*25224Smckusick 	for (controller = 0; controller < NDMZ; controller++) {
317*25224Smckusick 		ui = dmzinfo[controller];
318*25224Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
319*25224Smckusick 			continue;
320*25224Smckusick 		printf("dmz%d ", controller);
321*25224Smckusick 		dmz_addr = (struct dmzdevice *) ui->ui_addr;
322*25224Smckusick 
323*25224Smckusick 		for (octet = 0; octet < 3; octet++)
324*25224Smckusick 			if ((dmzact[controller] & (1 << octet)) != 0) {
325*25224Smckusick 				dmz_addr->octet[octet].octet_csr |= DMZ_IE;
326*25224Smckusick 				dmz_addr->octet[octet].octet_receive.octet_sato = SILO_TIMEOUT;
327*25224Smckusick 			}
328*25224Smckusick 
329*25224Smckusick 		unit = controller * 24;
330*25224Smckusick 
331*25224Smckusick 		/*
332*25224Smckusick 		 * If a unit is open or waiting for open to complete,
333*25224Smckusick 		 * reset it.
334*25224Smckusick 		 */
335*25224Smckusick 		for (i = 0; i < 24; i++) {
336*25224Smckusick 			dmz_softc[unit].dmz_state = 0;
337*25224Smckusick 			tp = &dmz_tty[unit];
338*25224Smckusick 			if (tp->t_state & (TS_ISOPEN | TS_WOPEN)) {
339*25224Smckusick 				dmzparam(unit);
340*25224Smckusick 				(void) dmzmctl(unit, DMZ_ON, DMSET);
341*25224Smckusick 				tp->t_state &= ~TS_BUSY;
342*25224Smckusick 				dmzstart(tp);
343*25224Smckusick 			}
344*25224Smckusick 			unit++;
345*25224Smckusick 		}
346*25224Smckusick 	}
347*25224Smckusick 	return;
348*25224Smckusick }
349*25224Smckusick 
350*25224Smckusick dmzread(device, uio)
351*25224Smckusick 	dev_t device;
352*25224Smckusick 	struct uio *uio;
353*25224Smckusick {
354*25224Smckusick 	register struct tty *tp;
355*25224Smckusick 	int xstatus;
356*25224Smckusick 
357*25224Smckusick 	tp = &dmz_tty[minor(device)];
358*25224Smckusick 	xstatus = (*linesw[tp->t_line].l_read)(tp, uio);
359*25224Smckusick 	return (xstatus);
360*25224Smckusick }
361*25224Smckusick 
362*25224Smckusick dmzwrite(device, uio)
363*25224Smckusick 	dev_t device;
364*25224Smckusick 	struct uio *uio;
365*25224Smckusick {
366*25224Smckusick 	register struct tty *tp;
367*25224Smckusick 	int xstatus;
368*25224Smckusick 
369*25224Smckusick 	tp = &dmz_tty[minor(device)];
370*25224Smckusick 	xstatus = (*linesw[tp->t_line].l_write)(tp, uio);
371*25224Smckusick 	return (xstatus);
372*25224Smckusick }
373*25224Smckusick 
374*25224Smckusick dmzrinta(controller)
375*25224Smckusick 	int controller;
376*25224Smckusick {
377*25224Smckusick 	dmzrint(controller, 0);
378*25224Smckusick }
379*25224Smckusick 
380*25224Smckusick dmzrintb(controller)
381*25224Smckusick 	int controller;
382*25224Smckusick {
383*25224Smckusick 	dmzrint(controller, 1);
384*25224Smckusick }
385*25224Smckusick 
386*25224Smckusick dmzrintc(controller)
387*25224Smckusick 	int controller;
388*25224Smckusick {
389*25224Smckusick 	dmzrint(controller, 2);
390*25224Smckusick }
391*25224Smckusick 
392*25224Smckusick dmzrint(controller, octet)
393*25224Smckusick 	int controller;
394*25224Smckusick 	register int octet;
395*25224Smckusick {
396*25224Smckusick 	register struct tty *tp;
397*25224Smckusick 	register int character;
398*25224Smckusick 	register struct dmzdevice *dmz_addr;
399*25224Smckusick 	register struct tty *tp0;
400*25224Smckusick 	register int unit;
401*25224Smckusick 	register struct uba_device *ui;
402*25224Smckusick 	int overrun, priority;
403*25224Smckusick 
404*25224Smckusick 	overrun = 0;
405*25224Smckusick 	ui = dmzinfo[controller];
406*25224Smckusick 	if (ui == 0 || ui->ui_alive == 0)
407*25224Smckusick 		return;
408*25224Smckusick 	dmz_addr = (struct dmzdevice *) ui->ui_addr;
409*25224Smckusick 	tp0 = &dmz_tty[controller * 24];
410*25224Smckusick 
411*25224Smckusick 	while ((character = dmz_addr->octet[octet].octet_receive.octet_rb) < 0) {
412*25224Smckusick 		unit = (character >> 8) & 07;	/* unit is bits 8-10 of rb */
413*25224Smckusick 		tp = tp0 + (octet * 8 + unit);
414*25224Smckusick 
415*25224Smckusick 		if (character & DMZ_DSC) {
416*25224Smckusick 			if ((dmzsoftCAR[controller] & (1 << (octet * 8 + unit))) == 0) {
417*25224Smckusick 				priority = spl5();
418*25224Smckusick 				dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | unit;
419*25224Smckusick 				if (dmz_addr->octet[octet].octet_rms & DMZ_CAR &&
420*25224Smckusick 				    (tp->t_state & TS_CARR_ON) == 0) {
421*25224Smckusick 					tp->t_state |= TS_CARR_ON;
422*25224Smckusick 					wakeup((caddr_t) &tp->t_rawq);
423*25224Smckusick 				} else {
424*25224Smckusick 					if (tp->t_state & TS_CARR_ON) {
425*25224Smckusick 						gsignal(tp->t_pgrp, SIGHUP);
426*25224Smckusick 						gsignal(tp->t_pgrp, SIGCONT);
427*25224Smckusick 						dmz_addr->octet[octet].octet_csr =
428*25224Smckusick 						   DMZ_IE | IR_LCTMR | unit;
429*25224Smckusick 						dmz_addr->octet[octet].octet_lctmr =
430*25224Smckusick 						   dmz_addr->octet[octet].octet_lctmr &
431*25224Smckusick 						   ((DMZ_OFF<<8) | 0xff);
432*25224Smckusick 						ttyflush(tp, FREAD|FWRITE);
433*25224Smckusick 					}
434*25224Smckusick 					tp->t_state &= ~TS_CARR_ON;
435*25224Smckusick 				}
436*25224Smckusick 				splx(priority);
437*25224Smckusick 			}
438*25224Smckusick 			continue;
439*25224Smckusick 		}
440*25224Smckusick 
441*25224Smckusick 		if ((tp->t_state & TS_ISOPEN) == 0) {
442*25224Smckusick 			wakeup((caddr_t) tp);
443*25224Smckusick 			continue;
444*25224Smckusick 		}
445*25224Smckusick 
446*25224Smckusick 		if (character & DMZ_PE) {
447*25224Smckusick 			if ((tp->t_flags & (EVENP | ODDP)) == EVENP ||
448*25224Smckusick 			    (tp->t_flags & (EVENP | ODDP)) == ODDP)
449*25224Smckusick 				continue;
450*25224Smckusick 		}
451*25224Smckusick 
452*25224Smckusick 		if ((character & DMZ_DO) && overrun == 0) {
453*25224Smckusick 			printf("dmz%d: silo overflow\n", controller);
454*25224Smckusick 			overrun = 1;
455*25224Smckusick 		}
456*25224Smckusick 
457*25224Smckusick 		if (character & DMZ_FE) {
458*25224Smckusick 			if (tp->t_flags & RAW)
459*25224Smckusick 				character = 0;
460*25224Smckusick 			else
461*25224Smckusick 				character = tp->t_intrc;
462*25224Smckusick 		}
463*25224Smckusick 
464*25224Smckusick 		(*linesw[tp->t_line].l_rint)(character, tp);
465*25224Smckusick 	}
466*25224Smckusick 
467*25224Smckusick 	return;
468*25224Smckusick }
469*25224Smckusick 
470*25224Smckusick dmzxinta(controller)
471*25224Smckusick 	int controller;
472*25224Smckusick {
473*25224Smckusick 	dmzxint(controller, 0);
474*25224Smckusick }
475*25224Smckusick 
476*25224Smckusick dmzxintb(controller)
477*25224Smckusick 	int controller;
478*25224Smckusick {
479*25224Smckusick 	dmzxint(controller, 1);
480*25224Smckusick }
481*25224Smckusick 
482*25224Smckusick dmzxintc(controller)
483*25224Smckusick 	int controller;
484*25224Smckusick {
485*25224Smckusick 	dmzxint(controller, 2);
486*25224Smckusick }
487*25224Smckusick 
488*25224Smckusick dmzxint(controller, octet)
489*25224Smckusick 	int controller;
490*25224Smckusick 	register int octet;
491*25224Smckusick {
492*25224Smckusick 	register struct tty *tp;
493*25224Smckusick 	register struct dmzdevice *dmz_addr;
494*25224Smckusick 	register struct uba_device *ui;
495*25224Smckusick 	register int unit, t;
496*25224Smckusick 	int priority;
497*25224Smckusick 
498*25224Smckusick 	ui = dmzinfo[controller];
499*25224Smckusick 	dmz_addr = (struct dmzdevice *)ui->ui_addr;
500*25224Smckusick 
501*25224Smckusick 	priority = spl5();
502*25224Smckusick 
503*25224Smckusick 	while ((t = dmz_addr->octet[octet].octet_csr) & DMZ_TRDY) {
504*25224Smckusick 		unit = controller * 24 + (octet * 8 + ((t>>8) & 07));
505*25224Smckusick 		tp = &dmz_tty[unit];
506*25224Smckusick 		tp->t_state &= ~TS_BUSY;
507*25224Smckusick 
508*25224Smckusick 		if (t & DMZ_NXM)
509*25224Smckusick 			printf("dmz%d: NXM line %d\n", controller,
510*25224Smckusick 				octet * 8 + (unit & 07));
511*25224Smckusick 
512*25224Smckusick 		if (tp->t_state & TS_FLUSH) {
513*25224Smckusick 			tp->t_state &= ~TS_FLUSH;
514*25224Smckusick 			dmz_addr->octet[octet].octet_csr =
515*25224Smckusick 				DMZ_IE | IR_LCTMR | (unit & 07);
516*25224Smckusick 			dmz_addr->octet[octet].octet_lctmr =
517*25224Smckusick 				(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
518*25224Smckusick 		} else
519*25224Smckusick 			if (dmz_softc[unit].dmz_state & ST_DMA)
520*25224Smckusick 				ndflush(&tp->t_outq, dmz_softc[unit].dmz_count);
521*25224Smckusick 		dmz_softc[unit].dmz_state = 0;
522*25224Smckusick 
523*25224Smckusick 		if (tp->t_line)
524*25224Smckusick 			(*linesw[tp->t_line].l_start)(tp);
525*25224Smckusick 		else
526*25224Smckusick 			dmzstart(tp);
527*25224Smckusick 	}
528*25224Smckusick 
529*25224Smckusick 	splx(priority);
530*25224Smckusick 	return;
531*25224Smckusick }
532*25224Smckusick 
533*25224Smckusick dmzstart(tp)
534*25224Smckusick 	register struct tty *tp;
535*25224Smckusick {
536*25224Smckusick 	register struct dmzdevice *dmz_addr;
537*25224Smckusick 	register int unit, nch, room;
538*25224Smckusick 	int controller, octet;
539*25224Smckusick 	int priority, car, use_dma;
540*25224Smckusick 	register int i;
541*25224Smckusick 	register char *cp;
542*25224Smckusick 
543*25224Smckusick 	unit = minor(tp->t_dev);
544*25224Smckusick 	controller = DMZ(unit);
545*25224Smckusick 	octet = OCTET(unit);
546*25224Smckusick 	dmz_addr = (struct dmzdevice *)tp->t_addr;
547*25224Smckusick 
548*25224Smckusick 	priority = spl5();
549*25224Smckusick 
550*25224Smckusick 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
551*25224Smckusick 		goto out;
552*25224Smckusick 
553*25224Smckusick 	/*
554*25224Smckusick 	 * If the transmitter has been disabled, reenable it.
555*25224Smckusick 	 * If the transmitter was disabled before the xint (the
556*25224Smckusick 	 * ST_INBUSY was still on), then reset the BUSY state and
557*25224Smckusick 	 * we will wait for the interrupt.  If !TS_BUSY, we already
558*25224Smckusick 	 * saw the interrupt so we can start another transmission.
559*25224Smckusick 	 */
560*25224Smckusick 	if (dmz_softc[unit].dmz_state & ST_TXOFF) {
561*25224Smckusick 		dmz_addr->octet[octet].octet_csr =
562*25224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
563*25224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
564*25224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
565*25224Smckusick 		dmz_softc[unit].dmz_state &= ~ST_TXOFF;
566*25224Smckusick 		if (dmz_softc[unit].dmz_state & ST_INBUSY) {
567*25224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_INBUSY;
568*25224Smckusick 			tp->t_state |= TS_BUSY;
569*25224Smckusick 			goto out;
570*25224Smckusick 		}
571*25224Smckusick 	}
572*25224Smckusick 
573*25224Smckusick 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
574*25224Smckusick 		if (tp->t_state & TS_ASLEEP) {
575*25224Smckusick 			tp->t_state &= ~TS_ASLEEP;
576*25224Smckusick 			wakeup((caddr_t)&tp->t_outq);
577*25224Smckusick 		}
578*25224Smckusick 		if (tp->t_wsel) {
579*25224Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
580*25224Smckusick 			tp->t_wsel = 0;
581*25224Smckusick 			tp->t_state &= ~TS_WCOLL;
582*25224Smckusick 		}
583*25224Smckusick 	}
584*25224Smckusick 
585*25224Smckusick 	if (tp->t_outq.c_cc == 0)
586*25224Smckusick 		goto out;
587*25224Smckusick 	if (tp->t_flags & (RAW | LITOUT))
588*25224Smckusick 		nch = ndqb(&tp->t_outq, 0);
589*25224Smckusick 	else {
590*25224Smckusick 		nch = ndqb(&tp->t_outq, 0200);
591*25224Smckusick 		if (nch == 0) {
592*25224Smckusick 			nch = getc(&tp->t_outq);
593*25224Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch & 0x7f)+6);
594*25224Smckusick 			tp->t_state |= TS_TIMEOUT;
595*25224Smckusick 			goto out;
596*25224Smckusick 		}
597*25224Smckusick 	}
598*25224Smckusick 
599*25224Smckusick 	/*
600*25224Smckusick 	 * Should we use DMA or SILO mode?
601*25224Smckusick 	 * If nch is greater than DO_DMA_COUNT then DMA.
602*25224Smckusick 	 */
603*25224Smckusick 	if (nch) {
604*25224Smckusick 		dmz_addr->octet[octet].octet_csr =
605*25224Smckusick 			DMZ_IE | IR_LCTMR | (unit & 07);
606*25224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
607*25224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_TE);
608*25224Smckusick 		tp->t_state |= TS_BUSY;
609*25224Smckusick 
610*25224Smckusick 		use_dma = FALSE;
611*25224Smckusick 		room = DMZ_SIZ;
612*25224Smckusick 
613*25224Smckusick 		if (nch > DO_DMA_COUNT)
614*25224Smckusick 			use_dma = TRUE;
615*25224Smckusick 
616*25224Smckusick 		if (use_dma && dmz_dma_on) {
617*25224Smckusick 			car = UBACVT(tp->t_outq.c_cf,
618*25224Smckusick 				dmzinfo[controller]->ui_ubanum);
619*25224Smckusick 			dmz_softc[unit].dmz_count = nch;
620*25224Smckusick 			dmz_softc[unit].dmz_state |= ST_DMA;
621*25224Smckusick 			dmz_addr->octet[octet].octet_csr =
622*25224Smckusick 				DMZ_IE | IR_TBA | (unit & 07);
623*25224Smckusick 			dmz_addr->octet[octet].octet_tba = car;
624*25224Smckusick 			dmz_addr->octet[octet].octet_tcc =
625*25224Smckusick 				((car >> 2) & 0xc000) | nch;
626*25224Smckusick 		} else {
627*25224Smckusick 			dmz_softc[unit].dmz_state &= ~ST_DMA;
628*25224Smckusick 			cp = tp->t_outq.c_cf;
629*25224Smckusick 			nch = MIN(nch, room);
630*25224Smckusick 			dmz_addr->octet[octet].octet_csr =
631*25224Smckusick 				DMZ_IE | IR_TBUF | (unit & 07);
632*25224Smckusick 			for (i = 0; i < nch; i++)
633*25224Smckusick 				dmz_addr->octet[octet].octet_tbf = *cp++ ;
634*25224Smckusick 			ndflush(&tp->t_outq, nch);
635*25224Smckusick 		}
636*25224Smckusick 	}
637*25224Smckusick 
638*25224Smckusick out:
639*25224Smckusick 	splx(priority);
640*25224Smckusick 	return;
641*25224Smckusick }
642*25224Smckusick 
643*25224Smckusick /* ARGSUSED */
644*25224Smckusick dmzstop(tp, flag)
645*25224Smckusick 	register struct tty *tp;
646*25224Smckusick {
647*25224Smckusick 	register struct dmzdevice *dmz_addr;
648*25224Smckusick 	register int unit, priority, octet;
649*25224Smckusick 
650*25224Smckusick 	priority = spl5();
651*25224Smckusick 	dmz_addr = (struct dmzdevice *) tp->t_addr;
652*25224Smckusick 	unit = minor(tp->t_dev);
653*25224Smckusick 	octet = OCTET(unit);
654*25224Smckusick 
655*25224Smckusick 	dmz_addr->octet[octet].octet_csr = IR_LCTMR | (unit & 07) | DMZ_IE;
656*25224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
657*25224Smckusick 		(dmz_addr->octet[octet].octet_lctmr & ~DMZ_TE);
658*25224Smckusick 	dmz_softc[unit].dmz_state |= ST_TXOFF;
659*25224Smckusick 	if ((tp->t_state & TS_TTSTOP) == 0) {
660*25224Smckusick 		tp->t_state |= (TS_FLUSH | TS_BUSY);
661*25224Smckusick 		dmz_addr->octet[octet].octet_lctmr =
662*25224Smckusick 			(dmz_addr->octet[octet].octet_lctmr | DMZ_FLS);
663*25224Smckusick 	} else if (tp->t_state & TS_BUSY) {
664*25224Smckusick 		dmz_softc[unit].dmz_state |= ST_INBUSY;
665*25224Smckusick 		tp->t_state &= ~TS_BUSY;
666*25224Smckusick 	}
667*25224Smckusick 
668*25224Smckusick 	splx(priority);
669*25224Smckusick 	return;
670*25224Smckusick }
671*25224Smckusick 
672*25224Smckusick /* ARGSUSED */
673*25224Smckusick dmzioctl(device, command, data, flag)
674*25224Smckusick 	dev_t device;
675*25224Smckusick 	caddr_t data;
676*25224Smckusick {
677*25224Smckusick 	register struct tty *tp;
678*25224Smckusick 	register int unit;
679*25224Smckusick 	int error;
680*25224Smckusick 
681*25224Smckusick 	unit = minor(device);
682*25224Smckusick 	tp = &dmz_tty[unit];
683*25224Smckusick 
684*25224Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, command, data, flag);
685*25224Smckusick 	if (error >= 0)
686*25224Smckusick 		return (error);
687*25224Smckusick 	error = ttioctl(tp, command, data, flag);
688*25224Smckusick 	if (error >= 0) {
689*25224Smckusick 		if (command == TIOCSETP || command == TIOCSETN)
690*25224Smckusick 			dmzparam(unit);
691*25224Smckusick 		return (error);
692*25224Smckusick 	}
693*25224Smckusick 
694*25224Smckusick 	switch (command) {
695*25224Smckusick 		case TIOCSBRK:
696*25224Smckusick 			(void) dmzmctl(device, DMZ_BRK, DMBIS);
697*25224Smckusick 			break;
698*25224Smckusick 		case TIOCCBRK:
699*25224Smckusick 			(void) dmzmctl(device, DMZ_BRK, DMBIC);
700*25224Smckusick 			break;
701*25224Smckusick 		case TIOCSDTR:
702*25224Smckusick 			(void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIS);
703*25224Smckusick 			break;
704*25224Smckusick 		case TIOCCDTR:
705*25224Smckusick 			(void) dmzmctl(device, DMZ_DTR | DMZ_RTS, DMBIC);
706*25224Smckusick 			break;
707*25224Smckusick 		case TIOCMSET:
708*25224Smckusick 			(void) dmzmctl(device, dmtodmz(*(int *)data), DMSET);
709*25224Smckusick 			break;
710*25224Smckusick 		case TIOCMBIS:
711*25224Smckusick 			(void) dmzmctl(device, dmtodmz(*(int *)data), DMBIS);
712*25224Smckusick 			break;
713*25224Smckusick 		case TIOCMBIC:
714*25224Smckusick 			(void) dmzmctl(device, dmtodmz(*(int *)data), DMBIC);
715*25224Smckusick 			break;
716*25224Smckusick 		case TIOCMGET:
717*25224Smckusick 			*(int *)data = dmztodm(dmzmctl(device, 0, DMGET));
718*25224Smckusick 			break;
719*25224Smckusick 		default:
720*25224Smckusick 			return (ENOTTY);
721*25224Smckusick 	}
722*25224Smckusick 	return (0);
723*25224Smckusick }
724*25224Smckusick 
725*25224Smckusick dmzmctl(device, bits, how)
726*25224Smckusick 	dev_t device;
727*25224Smckusick 	int bits, how;
728*25224Smckusick {
729*25224Smckusick 	register struct dmzdevice *dmz_addr;
730*25224Smckusick 	register int unit, modem_status, line_control;
731*25224Smckusick 	register int temp;
732*25224Smckusick 	int priority;
733*25224Smckusick 	int octet;
734*25224Smckusick 
735*25224Smckusick 	unit = minor(device);
736*25224Smckusick 	octet = OCTET(unit);
737*25224Smckusick 	dmz_addr = (struct dmzdevice *) dmz_tty[unit].t_addr;
738*25224Smckusick 
739*25224Smckusick 	priority = spl5();
740*25224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_RMS | (unit & 07);
741*25224Smckusick 	modem_status = dmz_addr->octet[octet].octet_rms << 8;
742*25224Smckusick 
743*25224Smckusick 	dmz_addr->octet[octet].octet_csr = DMZ_IE | IR_LCTMR | (unit & 07);
744*25224Smckusick 	temp = dmz_addr->octet[octet].octet_lctmr;
745*25224Smckusick 	modem_status |= ((temp>>8) & (0x1f));
746*25224Smckusick 	line_control = (temp & (0x1f));
747*25224Smckusick 
748*25224Smckusick 	if (line_control & DMZ_BRK)
749*25224Smckusick 		modem_status |= DMZ_BRK;
750*25224Smckusick 
751*25224Smckusick 	switch (how) {
752*25224Smckusick 		case DMSET:
753*25224Smckusick 			modem_status = (modem_status & 0xff00) | bits;
754*25224Smckusick 			break;
755*25224Smckusick 		case DMBIS:
756*25224Smckusick 			modem_status |= bits;
757*25224Smckusick 			break;
758*25224Smckusick 		case DMBIC:
759*25224Smckusick 			modem_status &= ~bits;
760*25224Smckusick 			break;
761*25224Smckusick 		case DMGET:
762*25224Smckusick 			(void) splx(priority);
763*25224Smckusick 			return (modem_status);
764*25224Smckusick 	}
765*25224Smckusick 
766*25224Smckusick 	if (modem_status & DMZ_BRK)
767*25224Smckusick 		line_control |= DMZ_RBK;
768*25224Smckusick 	else
769*25224Smckusick 		line_control &= ~DMZ_RBK;
770*25224Smckusick 	modem_status &= ~DMZ_BRK;
771*25224Smckusick 
772*25224Smckusick 	dmz_addr->octet[octet].octet_csr =
773*25224Smckusick 		DMZ_IE | IR_LCTMR | (unit & 07);
774*25224Smckusick 	dmz_addr->octet[octet].octet_lctmr =
775*25224Smckusick 		((modem_status & 0x1f) << 8) | (line_control & 0x3f);
776*25224Smckusick 
777*25224Smckusick 	(void) splx(priority);
778*25224Smckusick 	return (modem_status);
779*25224Smckusick }
780*25224Smckusick 
781*25224Smckusick /*
782*25224Smckusick  * Routine to convert modem status from dm to dmz format.
783*25224Smckusick  * Pull bits 1 & 3 through unchanged. If dm secondary transmit bit is set,
784*25224Smckusick  * and/or dm request to send bit is set, and/or dm user modem signal bit
785*25224Smckusick  * is set, set the corresponding dmz bits.
786*25224Smckusick  */
787*25224Smckusick dmtodmz(bits)
788*25224Smckusick 	register int bits;
789*25224Smckusick {
790*25224Smckusick 	register int b;
791*25224Smckusick 
792*25224Smckusick 	b = bits & 012;
793*25224Smckusick 	if (bits & DM_ST)
794*25224Smckusick 		b |= DMZ_RAT;
795*25224Smckusick 	if (bits & DM_RTS)
796*25224Smckusick 		b |= DMZ_RTS;
797*25224Smckusick 	if (bits & DM_USR)
798*25224Smckusick 		b |= DMZ_USW;
799*25224Smckusick 	return (b);
800*25224Smckusick }
801*25224Smckusick 
802*25224Smckusick /*
803*25224Smckusick  * Routine to convert modem status from dmz to dm format.  Pull bits 1 & 3
804*25224Smckusick  * through unchanged. Pull bits 11 - 15 through as bits 4 - 8 and set bit
805*25224Smckusick  * 0 to dm line enable.  If dmz user modem signal bit set, and/or  dmz
806*25224Smckusick  * request to send bit set, then set the corresponding dm bit also.
807*25224Smckusick  */
808*25224Smckusick dmztodm(bits)
809*25224Smckusick 	register int bits;
810*25224Smckusick {
811*25224Smckusick 	register int b;
812*25224Smckusick 
813*25224Smckusick 	b = (bits & 012) | ((bits >> 7) & 0760) | DM_LE;
814*25224Smckusick 	if (bits & DMZ_USR)
815*25224Smckusick 		b |= DM_USR;
816*25224Smckusick 	if (bits & DMZ_RTS)
817*25224Smckusick 		b |= DM_RTS;
818*25224Smckusick 	return (b);
819*25224Smckusick }
820*25224Smckusick #endif
821