xref: /original-bsd/sys/vax/uba/dhu.c (revision ec9268c1)
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.14 (Berkeley) 02/12/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/bkmac.h"
43 #include "sys/clist.h"
44 #include "sys/file.h"
45 #include "sys/uio.h"
46 
47 /*
48  * Definition of the driver for the auto-configuration program.
49  */
50 int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
51 struct	uba_device *dhuinfo[NDHU];
52 u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
53 struct	uba_driver dhudriver =
54 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
55 
56 #define	NDHULINE 	(NDHU*16)
57 
58 #define	UNIT(x)	(minor(x))
59 
60 #ifndef PORTSELECTOR
61 #define SPEED	TTYDEF_SPEED
62 #define LFLAG	TTYDEF_LFLAG
63 #else
64 #define SPEED	B4800
65 #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
66 #endif
67 
68 /*
69  * default receive silo timeout value -- valid values are 2..255
70  * number of ms. to delay between first char received and receive interrupt
71  *
72  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
73  */
74 #define	DHU_DEF_TIMO	20
75 
76 /*
77  * Other values for silo timeout register defined here but not used:
78  * receive interrupt only on modem control or silo alarm (3/4 full)
79  */
80 #define DHU_POLL_TIMO	0
81 /*
82  * receive interrupt immediately on receive character
83  */
84 #define DHU_NO_TIMO	1
85 
86 /*
87  * Local variables for the driver
88  */
89 /*
90  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
91  *	EXTA => 19200 baud
92  *	EXTB => 2000 baud
93  */
94 struct speedtab dhuspeedtab[] = {
95 	19200,	14,
96 	9600,	13,
97 	4800,	11,
98 	2400,	10,
99 	2000,	9,
100 	1800,	8,
101 	1200,	7,
102 	600,	6,
103 	300,	5,
104 	150,	4,
105 	134,	3,
106 	110,	2,
107 	75,	1,
108 	0,	0,
109 	EXTA,	14,
110 	EXTB,	9,
111 	-1,	-1,
112 };
113 
114 short	dhusoftCAR[NDHU];
115 
116 struct	tty dhu_tty[NDHULINE];
117 int	ndhu = NDHULINE;
118 int	dhuact;				/* mask of active dhu's */
119 int	dhustart(), ttrstrt();
120 
121 /*
122  * The clist space is mapped by one terminal driver onto each UNIBUS.
123  * The identity of the board which allocated resources is recorded,
124  * so the process may be repeated after UNIBUS resets.
125  * The UBACVT macro converts a clist space address for unibus uban
126  * into an i/o space address for the DMA routine.
127  */
128 int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
129 int	cbase[NUBA];		/* base address of clists in unibus map */
130 #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
131 
132 /*
133  * Routine for configuration to force a dhu to interrupt.
134  */
135 /*ARGSUSED*/
136 dhuprobe(reg)
137 	caddr_t reg;
138 {
139 	register int br, cvec;		/* these are ``value-result'' */
140 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
141 	int i;
142 
143 #ifdef lint
144 	br = 0; cvec = br; br = cvec;
145 	if (ndhu == 0) ndhu = 1;
146 	dhurint(0); dhuxint(0);
147 #endif
148 	/*
149 	 * The basic idea here is:
150 	 *	do a self-test by setting the Master-Reset bit
151 	 *	if this fails, then return
152 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
153 	 *	therefore ask for a  Received-Data-Available interrupt
154 	 *	wait for it...
155 	 *	reset the interrupt-enable bit and flush out the diag. codes
156 	 */
157 	dhuaddr->dhucsr = DHU_CS_MCLR;
158 	for (i = 0; i < 1000; i++) {
159 		DELAY(10000);
160 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
161 			break;
162 	}
163 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
164 		return(0);
165 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
166 		return(0);
167 	dhuaddr->dhucsr = DHU_CS_RIE;
168 	DELAY(1000);
169 	dhuaddr->dhucsr = 0;
170 	while (dhuaddr->dhurbuf < 0)
171 		/* void */;
172 	return (sizeof(struct dhudevice));
173 }
174 
175 /*
176  * Routine called to attach a dhu.
177  */
178 dhuattach(ui)
179 	struct uba_device *ui;
180 {
181 
182 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
183 	cbase[ui->ui_ubanum] = -1;
184 	dhu_uballoc[ui->ui_ubanum] = -1;
185 }
186 
187 /*
188  * Open a DHU11 line, mapping the clist onto the uba if this
189  * is the first dhu on this uba.  Turn on this dhu if this is
190  * the first use of it.
191  */
192 /*ARGSUSED*/
193 dhuopen(dev, flag)
194 	dev_t dev;
195 {
196 	register struct tty *tp;
197 	register int unit, dhu;
198 	register struct dhudevice *addr;
199 	register struct uba_device *ui;
200 	int s, error = 0;
201 	extern dhuparam();
202 
203 	unit = UNIT(dev);
204 	dhu = unit >> 4;
205 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
206 		return (ENXIO);
207 	tp = &dhu_tty[unit];
208 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
209 		return (EBUSY);
210 	addr = (struct dhudevice *)ui->ui_addr;
211 	tp->t_addr = (caddr_t)addr;
212 	tp->t_oproc = dhustart;
213 	tp->t_param = dhuparam;
214 	/*
215 	 * While setting up state for this uba and this dhu,
216 	 * block uba resets which can clear the state.
217 	 */
218 	s = spl5();
219 	if (cbase[ui->ui_ubanum] == -1) {
220 		dhu_uballoc[ui->ui_ubanum] = dhu;
221 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
222 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
223 	}
224 	if ((dhuact&(1<<dhu)) == 0) {
225 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
226 		addr->dhutimo = DHU_DEF_TIMO;
227 		dhuact |= (1<<dhu);
228 		/* anything else to configure whole board */
229 	}
230 	(void) splx(s);
231 	/*
232 	 * If this is first open, initialize tty state to default.
233 	 */
234 	if ((tp->t_state&TS_ISOPEN) == 0) {
235 		tp->t_state |= TS_WOPEN;
236 		ttychars(tp);
237 #ifndef PORTSELECTOR
238 		if (tp->t_ospeed == 0) {
239 #endif
240 			tp->t_ispeed = SPEED;
241 			tp->t_ospeed = SPEED;
242 			ttsetwater(tp);
243 			tp->t_iflag = TTYDEF_IFLAG;
244 			tp->t_oflag = TTYDEF_OFLAG;
245 			tp->t_lflag = LFLAG;
246 			tp->t_cflag = TTYDEF_CFLAG;
247 #ifdef PORTSELECTOR
248 			tp->t_cflag |= HUPCL;
249 #else
250 		}
251 #endif
252 		tp->t_dev = dev;
253 		dhuparam(tp, &tp->t_termios);
254 	}
255 	/*
256 	 * Wait for carrier, then process line discipline specific open.
257 	 */
258 	s = spltty();
259 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
260 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
261 		tp->t_state |= TS_CARR_ON;
262 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
263 	    (tp->t_state & TS_CARR_ON) == 0) {
264 		tp->t_state |= TS_WOPEN;
265 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
266 		    ttopen, 0))
267 			break;
268 	}
269 	(void) splx(s);
270 	if (error)
271 		return (error);
272 	return ((*linesw[tp->t_line].l_open)(dev, tp));
273 }
274 
275 /*
276  * Close a DHU11 line, turning off the modem control.
277  */
278 /*ARGSUSED*/
279 dhuclose(dev, flag)
280 	dev_t dev;
281 	int flag;
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);
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