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