xref: /original-bsd/sys/vax/uba/dhu.c (revision 42c7e7a1)
1 /*
2  * Copyright (c) 1985, 1986 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  *	@(#)dhu.c	7.16 (Berkeley) 05/16/91
7  */
8 
9 /*
10  * based on	dh.c 6.3	84/03/15
11  * and on	dmf.c	6.2	84/02/16
12  *
13  * Dave Johnson, Brown University Computer Science
14  *	ddj%brown@csnet-relay
15  */
16 
17 #include "dhu.h"
18 #if NDHU > 0
19 /*
20  * DHU-11 driver
21  */
22 #include "../include/pte.h"
23 
24 #include "sys/param.h"
25 #include "sys/conf.h"
26 #include "sys/user.h"
27 #include "sys/proc.h"
28 #include "sys/ioctl.h"
29 #include "sys/tty.h"
30 #include "sys/ttydefaults.h"
31 #include "sys/map.h"
32 #include "sys/buf.h"
33 #include "sys/vm.h"
34 #include "sys/kernel.h"
35 #include "sys/syslog.h"
36 
37 #include "uba.h"
38 #include "ubareg.h"
39 #include "ubavar.h"
40 #include "dhureg.h"
41 
42 #include "sys/clist.h"
43 #include "sys/file.h"
44 #include "sys/uio.h"
45 
46 /*
47  * Definition of the driver for the auto-configuration program.
48  */
49 int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
50 struct	uba_device *dhuinfo[NDHU];
51 u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
52 struct	uba_driver dhudriver =
53 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
54 
55 #define	NDHULINE 	(NDHU*16)
56 
57 #define	UNIT(x)	(minor(x))
58 
59 #ifndef PORTSELECTOR
60 #define SPEED	TTYDEF_SPEED
61 #define LFLAG	TTYDEF_LFLAG
62 #else
63 #define SPEED	B4800
64 #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
65 #endif
66 
67 /*
68  * default receive silo timeout value -- valid values are 2..255
69  * number of ms. to delay between first char received and receive interrupt
70  *
71  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
72  */
73 #define	DHU_DEF_TIMO	20
74 
75 /*
76  * Other values for silo timeout register defined here but not used:
77  * receive interrupt only on modem control or silo alarm (3/4 full)
78  */
79 #define DHU_POLL_TIMO	0
80 /*
81  * receive interrupt immediately on receive character
82  */
83 #define DHU_NO_TIMO	1
84 
85 /*
86  * Local variables for the driver
87  */
88 /*
89  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
90  *	EXTA => 19200 baud
91  *	EXTB => 2000 baud
92  */
93 struct speedtab dhuspeedtab[] = {
94 	19200,	14,
95 	9600,	13,
96 	4800,	11,
97 	2400,	10,
98 	2000,	9,
99 	1800,	8,
100 	1200,	7,
101 	600,	6,
102 	300,	5,
103 	150,	4,
104 	134,	3,
105 	110,	2,
106 	75,	1,
107 	0,	0,
108 	EXTA,	14,
109 	EXTB,	9,
110 	-1,	-1,
111 };
112 
113 short	dhusoftCAR[NDHU];
114 
115 struct	tty dhu_tty[NDHULINE];
116 int	ndhu = NDHULINE;
117 int	dhuact;				/* mask of active dhu's */
118 int	dhustart(), ttrstrt();
119 
120 /*
121  * The clist space is mapped by one terminal driver onto each UNIBUS.
122  * The identity of the board which allocated resources is recorded,
123  * so the process may be repeated after UNIBUS resets.
124  * The UBACVT macro converts a clist space address for unibus uban
125  * into an i/o space address for the DMA routine.
126  */
127 int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
128 int	cbase[NUBA];		/* base address of clists in unibus map */
129 #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
130 
131 /*
132  * Routine for configuration to force a dhu to interrupt.
133  */
134 /*ARGSUSED*/
135 dhuprobe(reg)
136 	caddr_t reg;
137 {
138 	register int br, cvec;		/* these are ``value-result'' */
139 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
140 	int i;
141 
142 #ifdef lint
143 	br = 0; cvec = br; br = cvec;
144 	if (ndhu == 0) ndhu = 1;
145 	dhurint(0); dhuxint(0);
146 #endif
147 	/*
148 	 * The basic idea here is:
149 	 *	do a self-test by setting the Master-Reset bit
150 	 *	if this fails, then return
151 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
152 	 *	therefore ask for a  Received-Data-Available interrupt
153 	 *	wait for it...
154 	 *	reset the interrupt-enable bit and flush out the diag. codes
155 	 */
156 	dhuaddr->dhucsr = DHU_CS_MCLR;
157 	for (i = 0; i < 1000; i++) {
158 		DELAY(10000);
159 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
160 			break;
161 	}
162 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
163 		return(0);
164 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
165 		return(0);
166 	dhuaddr->dhucsr = DHU_CS_RIE;
167 	DELAY(1000);
168 	dhuaddr->dhucsr = 0;
169 	while (dhuaddr->dhurbuf < 0)
170 		/* void */;
171 	return (sizeof(struct dhudevice));
172 }
173 
174 /*
175  * Routine called to attach a dhu.
176  */
177 dhuattach(ui)
178 	struct uba_device *ui;
179 {
180 
181 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
182 	cbase[ui->ui_ubanum] = -1;
183 	dhu_uballoc[ui->ui_ubanum] = -1;
184 }
185 
186 /*
187  * Open a DHU11 line, mapping the clist onto the uba if this
188  * is the first dhu on this uba.  Turn on this dhu if this is
189  * the first use of it.
190  */
191 /*ARGSUSED*/
192 dhuopen(dev, flag)
193 	dev_t dev;
194 {
195 	register struct tty *tp;
196 	register int unit, dhu;
197 	register struct dhudevice *addr;
198 	register struct uba_device *ui;
199 	int s, error = 0;
200 	extern dhuparam();
201 
202 	unit = UNIT(dev);
203 	dhu = unit >> 4;
204 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
205 		return (ENXIO);
206 	tp = &dhu_tty[unit];
207 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
208 		return (EBUSY);
209 	addr = (struct dhudevice *)ui->ui_addr;
210 	tp->t_addr = (caddr_t)addr;
211 	tp->t_oproc = dhustart;
212 	tp->t_param = dhuparam;
213 	/*
214 	 * While setting up state for this uba and this dhu,
215 	 * block uba resets which can clear the state.
216 	 */
217 	s = spl5();
218 	if (cbase[ui->ui_ubanum] == -1) {
219 		dhu_uballoc[ui->ui_ubanum] = dhu;
220 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
221 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
222 	}
223 	if ((dhuact&(1<<dhu)) == 0) {
224 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
225 		addr->dhutimo = DHU_DEF_TIMO;
226 		dhuact |= (1<<dhu);
227 		/* anything else to configure whole board */
228 	}
229 	(void) splx(s);
230 	/*
231 	 * If this is first open, initialize tty state to default.
232 	 */
233 	if ((tp->t_state&TS_ISOPEN) == 0) {
234 		tp->t_state |= TS_WOPEN;
235 		ttychars(tp);
236 #ifndef PORTSELECTOR
237 		if (tp->t_ospeed == 0) {
238 #endif
239 			tp->t_ispeed = SPEED;
240 			tp->t_ospeed = SPEED;
241 			ttsetwater(tp);
242 			tp->t_iflag = TTYDEF_IFLAG;
243 			tp->t_oflag = TTYDEF_OFLAG;
244 			tp->t_lflag = LFLAG;
245 			tp->t_cflag = TTYDEF_CFLAG;
246 #ifdef PORTSELECTOR
247 			tp->t_cflag |= HUPCL;
248 #else
249 		}
250 #endif
251 		tp->t_dev = dev;
252 		dhuparam(tp, &tp->t_termios);
253 	}
254 	/*
255 	 * Wait for carrier, then process line discipline specific open.
256 	 */
257 	s = spltty();
258 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
259 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
260 		tp->t_state |= TS_CARR_ON;
261 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
262 	    (tp->t_state & TS_CARR_ON) == 0) {
263 		tp->t_state |= TS_WOPEN;
264 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
265 		    ttopen, 0))
266 			break;
267 	}
268 	(void) splx(s);
269 	if (error)
270 		return (error);
271 	return ((*linesw[tp->t_line].l_open)(dev, tp));
272 }
273 
274 /*
275  * Close a DHU11 line, turning off the modem control.
276  */
277 /*ARGSUSED*/
278 dhuclose(dev, flag, mode, p)
279 	dev_t dev;
280 	int flag, mode;
281 	struct proc *p;
282 {
283 	register struct tty *tp;
284 	register unit;
285 
286 	unit = UNIT(dev);
287 	tp = &dhu_tty[unit];
288 	(*linesw[tp->t_line].l_close)(tp, flag);
289 	(void) dhumctl(unit, DHU_BRK, DMBIC);
290 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
291 	    (tp->t_state&TS_ISOPEN) == 0) {
292 #ifdef PORTSELECTOR
293 		(void) dhumctl(unit, DHU_OFF, DMSET);
294 		/* Hold DTR low for 0.5 seconds */
295 		(void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2);
296 #else
297 		(void) dhumctl(unit, DHU_OFF, DMSET);
298 #endif PORTSELECTOR
299 	}
300 	return (ttyclose(tp));
301 }
302 
303 dhuread(dev, uio, flag)
304 	dev_t dev;
305 	struct uio *uio;
306 {
307 	register struct tty *tp = &dhu_tty[UNIT(dev)];
308 
309 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
310 }
311 
312 dhuwrite(dev, uio, flag)
313 	dev_t dev;
314 	struct uio *uio;
315 {
316 	register struct tty *tp = &dhu_tty[UNIT(dev)];
317 
318 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
319 }
320 
321 /*
322  * DHU11 receiver interrupt.
323  */
324 dhurint(dhu)
325 	int dhu;
326 {
327 	register struct tty *tp;
328 	register creg, c;
329 	register struct dhudevice *addr;
330 	register struct tty *tp0;
331 	register struct uba_device *ui;
332 	register line;
333 	int overrun = 0;
334 
335 #ifdef QBA
336 	(void) spltty();
337 #endif
338 	ui = dhuinfo[dhu];
339 	if (ui == 0 || ui->ui_alive == 0)
340 		return;
341 	addr = (struct dhudevice *)ui->ui_addr;
342 	tp0 = &dhu_tty[dhu<<4];
343 	/*
344 	 * Loop fetching characters from the silo for this
345 	 * dhu until there are no more in the silo.
346 	 */
347 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
348 		line = DHU_RX_LINE(creg);
349 		tp = tp0 + line;
350 		c = creg & 0xff;
351 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
352 			/*
353 			 * modem changed or diag info
354 			 */
355 			if (creg & DHU_RB_DIAG) {
356 				/* decode diagnostic messages */
357 				continue;
358 			}
359 			if (creg & DHU_ST_DCD)
360 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
361 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
362 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
363 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
364 			continue;
365 		}
366 		if ((tp->t_state&TS_ISOPEN) == 0) {
367 			wakeup((caddr_t)&tp->t_rawq);
368 #ifdef PORTSELECTOR
369 			if ((tp->t_state&TS_WOPEN) == 0)
370 #endif
371 				continue;
372 		}
373 		if (creg & DHU_RB_PE)
374 			c |= TTY_PE;
375 		if (creg & DHU_RB_DO && overrun == 0) {
376 			log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
377 			overrun = 1;
378 		}
379 		if (creg & DHU_RB_FE)
380 			c |= TTY_FE;
381 
382 		(*linesw[tp->t_line].l_rint)(c, tp);
383 	}
384 }
385 
386 /*
387  * Ioctl for DHU11.
388  */
389 /*ARGSUSED*/
390 dhuioctl(dev, cmd, data, flag)
391 	caddr_t data;
392 {
393 	register struct tty *tp;
394 	register int unit = UNIT(dev);
395 	int error;
396 
397 	tp = &dhu_tty[unit];
398 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
399 	if (error >= 0)
400 		return (error);
401 	error = ttioctl(tp, cmd, data, flag);
402 	if (error >= 0)
403 		return (error);
404 
405 	switch (cmd) {
406 	case TIOCSBRK:
407 		(void) dhumctl(unit, DHU_BRK, DMBIS);
408 		break;
409 
410 	case TIOCCBRK:
411 		(void) dhumctl(unit, DHU_BRK, DMBIC);
412 		break;
413 
414 	case TIOCSDTR:
415 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
416 		break;
417 
418 	case TIOCCDTR:
419 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
420 		break;
421 
422 	case TIOCMSET:
423 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
424 		break;
425 
426 	case TIOCMBIS:
427 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
428 		break;
429 
430 	case TIOCMBIC:
431 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
432 		break;
433 
434 	case TIOCMGET:
435 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
436 		break;
437 	default:
438 		return (ENOTTY);
439 	}
440 	return (0);
441 }
442 
443 dmtodhu(bits)
444 	register int bits;
445 {
446 	register int b = 0;
447 
448 	if (bits & DML_RTS) b |= DHU_RTS;
449 	if (bits & DML_DTR) b |= DHU_DTR;
450 	if (bits & DML_LE) b |= DHU_LE;
451 	return(b);
452 }
453 
454 dhutodm(bits)
455 	register int bits;
456 {
457 	register int b = 0;
458 
459 	if (bits & DHU_DSR) b |= DML_DSR;
460 	if (bits & DHU_RNG) b |= DML_RNG;
461 	if (bits & DHU_CAR) b |= DML_CAR;
462 	if (bits & DHU_CTS) b |= DML_CTS;
463 	if (bits & DHU_RTS) b |= DML_RTS;
464 	if (bits & DHU_DTR) b |= DML_DTR;
465 	if (bits & DHU_LE) b |= DML_LE;
466 	return(b);
467 }
468 
469 
470 /*
471  * Set parameters from open or stty into the DHU hardware
472  * registers.  Impossible values for speed or character
473  * size are ignored and not copied back into tp.
474  */
475 dhuparam(tp, want)
476 	register struct tty *tp;
477 	register struct termios *want;
478 {
479 	register int unit = UNIT(tp->t_dev);
480 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
481 	register int lpar;
482 	register long cflag;
483 	register int incode, outcode;
484 	int s;
485 
486 	/*
487 	 * Block interrupts so parameters will be set
488 	 * before the line interrupts.
489 	 */
490 	s = spltty();
491 
492 	if (want->c_ospeed == 0) {
493 		tp->t_ospeed = 0;
494 		tp->t_cflag |= HUPCL;
495 		(void)dhumctl(unit, DHU_OFF, DMSET);
496 		splx(s);
497 		return (0);
498 	}
499 
500 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
501 		tp->t_ospeed = want->c_ospeed;
502 	else
503 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
504 
505 	if (want->c_ispeed == 0) {
506 		tp->t_ispeed = 0;
507 		incode = outcode;
508 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
509 		tp->t_ispeed = want->c_ispeed;
510 	else
511 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
512 
513 	lpar = ((char)outcode<<12) | ((char)incode<<8);
514 
515 	switch (want->c_cflag&CSIZE) {
516 	case CS6: case CS7: case CS8:
517 		tp->t_cflag =  want->c_cflag;
518 		break;
519 	default:
520 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
521 	}
522 	cflag = tp->t_cflag;
523 
524 	switch(cflag&CSIZE) {
525 	case CS6:
526 		lpar |= DHU_LP_BITS6;
527 		break;
528 	case CS7:
529 		lpar |= DHU_LP_BITS7;
530 		break;
531 	case CS8:
532 		lpar |= DHU_LP_BITS8;
533 		break;
534 	}
535 	if (cflag&PARENB) {
536 		lpar |= DHU_LP_PENABLE;
537 		if ((cflag&PARODD) == 0)
538 			lpar |= DHU_LP_EPAR;
539 	}
540 	if (cflag&CSTOPB)
541 		lpar |= DHU_LP_TWOSB;
542 
543 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
544 	addr->dhulpr = lpar;
545 	splx(s);
546 	return (0);
547 }
548 
549 /*
550  * DHU11 transmitter interrupt.
551  * Restart each line which used to be active but has
552  * terminated transmission since the last interrupt.
553  */
554 dhuxint(dhu)
555 	int dhu;
556 {
557 	register struct tty *tp;
558 	register struct dhudevice *addr;
559 	register struct tty *tp0;
560 	register struct uba_device *ui;
561 	register int line, t;
562 	u_short cntr;
563 
564 #ifdef QBA
565 	(void) spl5();
566 #endif
567 	ui = dhuinfo[dhu];
568 	tp0 = &dhu_tty[dhu<<4];
569 	addr = (struct dhudevice *)ui->ui_addr;
570 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
571 		line = DHU_TX_LINE(t);
572 		tp = tp0 + line;
573 		tp->t_state &= ~TS_BUSY;
574 		if (t & DHU_CSH_NXM) {
575 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
576 			/* SHOULD RESTART OR SOMETHING... */
577 		}
578 		if (tp->t_state&TS_FLUSH)
579 			tp->t_state &= ~TS_FLUSH;
580 		else {
581 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
582 			/*
583 			 * Do arithmetic in a short to make up
584 			 * for lost 16&17 bits.
585 			 */
586 			cntr = addr->dhubar1 -
587 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
588 			ndflush(&tp->t_outq, (int)cntr);
589 		}
590 		if (tp->t_line)
591 			(*linesw[tp->t_line].l_start)(tp);
592 		else
593 			dhustart(tp);
594 	}
595 }
596 
597 /*
598  * Start (restart) transmission on the given DHU11 line.
599  */
600 dhustart(tp)
601 	register struct tty *tp;
602 {
603 	register struct dhudevice *addr;
604 	register int car, dhu, unit, nch;
605 	int s;
606 
607 	unit = minor(tp->t_dev);
608 	dhu = unit >> 4;
609 	unit &= 0xf;
610 	addr = (struct dhudevice *)tp->t_addr;
611 
612 	/*
613 	 * Must hold interrupts in following code to prevent
614 	 * state of the tp from changing.
615 	 */
616 	s = spl5();
617 	/*
618 	 * If it's currently active, or delaying, no need to do anything.
619 	 */
620 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
621 		goto out;
622 	/*
623 	 * If there are sleepers, and output has drained below low
624 	 * water mark, wake up the sleepers..
625 	 */
626 	if (tp->t_outq.c_cc <= tp->t_lowat) {
627 		if (tp->t_state&TS_ASLEEP) {
628 			tp->t_state &= ~TS_ASLEEP;
629 			wakeup((caddr_t)&tp->t_outq);
630 		}
631 		if (tp->t_wsel) {
632 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
633 			tp->t_wsel = 0;
634 			tp->t_state &= ~TS_WCOLL;
635 		}
636 	}
637 	/*
638 	 * Now restart transmission unless the output queue is
639 	 * empty.
640 	 */
641 	if (tp->t_outq.c_cc == 0)
642 		goto out;
643 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
644 		nch = ndqb(&tp->t_outq, 0);
645 	else {
646 		nch = ndqb(&tp->t_outq, 0200);
647 		/*
648 		 * If first thing on queue is a delay process it.
649 		 */
650 		if (nch == 0) {
651 			nch = getc(&tp->t_outq);
652 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
653 			tp->t_state |= TS_TIMEOUT;
654 			goto out;
655 		}
656 	}
657 	/*
658 	 * If characters to transmit, restart transmission.
659 	 */
660 	if (nch) {
661 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
662 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
663 		addr->dhulcr &= ~DHU_LC_TXABORT;
664 		addr->dhubcr = nch;
665 		addr->dhubar1 = car;
666 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
667 					DHU_BA2_DMAGO;
668 		tp->t_state |= TS_BUSY;
669 	}
670 out:
671 	splx(s);
672 }
673 
674 /*
675  * Stop output on a line, e.g. for ^S/^Q or output flush.
676  */
677 /*ARGSUSED*/
678 dhustop(tp, flag)
679 	register struct tty *tp;
680 {
681 	register struct dhudevice *addr;
682 	register int unit, s;
683 
684 	addr = (struct dhudevice *)tp->t_addr;
685 	/*
686 	 * Block input/output interrupts while messing with state.
687 	 */
688 	s = spl5();
689 	if (tp->t_state & TS_BUSY) {
690 		/*
691 		 * Device is transmitting; stop output
692 		 * by selecting the line and setting the
693 		 * abort xmit bit.  We will get an xmit interrupt,
694 		 * where we will figure out where to continue the
695 		 * next time the transmitter is enabled.  If
696 		 * TS_FLUSH is set, the outq will be flushed.
697 		 * In either case, dhustart will clear the TXABORT bit.
698 		 */
699 		unit = minor(tp->t_dev);
700 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
701 		addr->dhulcr |= DHU_LC_TXABORT;
702 		if ((tp->t_state&TS_TTSTOP)==0)
703 			tp->t_state |= TS_FLUSH;
704 	}
705 	(void) splx(s);
706 }
707 
708 /*
709  * DHU11 modem control
710  */
711 dhumctl(dev, bits, how)
712 	dev_t dev;
713 	int bits, how;
714 {
715 	register struct dhudevice *dhuaddr;
716 	register int unit, mbits;
717 	int s;
718 
719 	unit = UNIT(dev);
720 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
721 	unit &= 0xf;
722 	s = spl5();
723 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
724 	/*
725 	 * combine byte from stat register (read only, bits 16..23)
726 	 * with lcr register (read write, bits 0..15).
727 	 */
728 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
729 	switch (how) {
730 	case DMSET:
731 		mbits = (mbits & 0xff0000) | bits;
732 		break;
733 
734 	case DMBIS:
735 		mbits |= bits;
736 		break;
737 
738 	case DMBIC:
739 		mbits &= ~bits;
740 		break;
741 
742 	case DMGET:
743 		(void) splx(s);
744 		return(mbits);
745 	}
746 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
747 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
748 	(void) splx(s);
749 	return(mbits);
750 }
751 
752 /*
753  * Reset state of driver if UBA reset was necessary.
754  * Reset the line and modem control registers.
755  * restart transmitters.
756  */
757 dhureset(uban)
758 	int uban;
759 {
760 	register int dhu, unit;
761 	register struct tty *tp;
762 	register struct uba_device *ui;
763 	register struct dhudevice *addr;
764 	int i;
765 
766 	for (dhu = 0; dhu < NDHU; dhu++) {
767 		ui = dhuinfo[dhu];
768 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
769 			continue;
770 		printf(" dhu%d", dhu);
771 		if (dhu_uballoc[uban] == dhu) {
772 			int info;
773 
774 			info = uballoc(uban, (caddr_t)cfree,
775 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
776 			if (info)
777 				cbase[uban] = UBAI_ADDR(info);
778 			else {
779 				printf(" [can't get uba map]");
780 				cbase[uban] = -1;
781 			}
782 		}
783 		addr = (struct dhudevice *)ui->ui_addr;
784 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
785 		addr->dhutimo = DHU_DEF_TIMO;
786 		unit = dhu * 16;
787 		for (i = 0; i < 16; i++) {
788 			tp = &dhu_tty[unit];
789 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
790 				dhuparam(tp, &tp->t_termios);
791 				(void)dhumctl(unit, DHU_ON, DMSET);
792 				tp->t_state &= ~TS_BUSY;
793 				dhustart(tp);
794 			}
795 			unit++;
796 		}
797 	}
798 }
799 #endif
800