xref: /original-bsd/sys/vax/uba/dhu.c (revision d14ae743)
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.11 (Berkeley) 06/06/90
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 "machine/pte.h"
23 
24 #include "param.h"
25 #include "conf.h"
26 #include "user.h"
27 #include "proc.h"
28 #include "ioctl.h"
29 #include "tty.h"
30 #include "ttydefaults.h"
31 #include "map.h"
32 #include "buf.h"
33 #include "vm.h"
34 #include "kernel.h"
35 #include "syslog.h"
36 
37 #include "uba.h"
38 #include "ubareg.h"
39 #include "ubavar.h"
40 #include "dhureg.h"
41 
42 #include "bkmac.h"
43 #include "clist.h"
44 #include "file.h"
45 #include "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 		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 = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
265 				    ttopen, 0)) ||
266 		    (error = ttclosed(tp)))
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;
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 }
547 
548 /*
549  * DHU11 transmitter interrupt.
550  * Restart each line which used to be active but has
551  * terminated transmission since the last interrupt.
552  */
553 dhuxint(dhu)
554 	int dhu;
555 {
556 	register struct tty *tp;
557 	register struct dhudevice *addr;
558 	register struct tty *tp0;
559 	register struct uba_device *ui;
560 	register int line, t;
561 	u_short cntr;
562 
563 #ifdef QBA
564 	(void) spl5();
565 #endif
566 	ui = dhuinfo[dhu];
567 	tp0 = &dhu_tty[dhu<<4];
568 	addr = (struct dhudevice *)ui->ui_addr;
569 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
570 		line = DHU_TX_LINE(t);
571 		tp = tp0 + line;
572 		tp->t_state &= ~TS_BUSY;
573 		if (t & DHU_CSH_NXM) {
574 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
575 			/* SHOULD RESTART OR SOMETHING... */
576 		}
577 		if (tp->t_state&TS_FLUSH)
578 			tp->t_state &= ~TS_FLUSH;
579 		else {
580 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
581 			/*
582 			 * Do arithmetic in a short to make up
583 			 * for lost 16&17 bits.
584 			 */
585 			cntr = addr->dhubar1 -
586 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
587 			ndflush(&tp->t_outq, (int)cntr);
588 		}
589 		if (tp->t_line)
590 			(*linesw[tp->t_line].l_start)(tp);
591 		else
592 			dhustart(tp);
593 	}
594 }
595 
596 /*
597  * Start (restart) transmission on the given DHU11 line.
598  */
599 dhustart(tp)
600 	register struct tty *tp;
601 {
602 	register struct dhudevice *addr;
603 	register int car, dhu, unit, nch;
604 	int s;
605 
606 	unit = minor(tp->t_dev);
607 	dhu = unit >> 4;
608 	unit &= 0xf;
609 	addr = (struct dhudevice *)tp->t_addr;
610 
611 	/*
612 	 * Must hold interrupts in following code to prevent
613 	 * state of the tp from changing.
614 	 */
615 	s = spl5();
616 	/*
617 	 * If it's currently active, or delaying, no need to do anything.
618 	 */
619 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
620 		goto out;
621 	/*
622 	 * If there are sleepers, and output has drained below low
623 	 * water mark, wake up the sleepers..
624 	 */
625 	if (tp->t_outq.c_cc <= tp->t_lowat) {
626 		if (tp->t_state&TS_ASLEEP) {
627 			tp->t_state &= ~TS_ASLEEP;
628 			wakeup((caddr_t)&tp->t_outq);
629 		}
630 		if (tp->t_wsel) {
631 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
632 			tp->t_wsel = 0;
633 			tp->t_state &= ~TS_WCOLL;
634 		}
635 	}
636 	/*
637 	 * Now restart transmission unless the output queue is
638 	 * empty.
639 	 */
640 	if (tp->t_outq.c_cc == 0)
641 		goto out;
642 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
643 		nch = ndqb(&tp->t_outq, 0);
644 	else {
645 		nch = ndqb(&tp->t_outq, 0200);
646 		/*
647 		 * If first thing on queue is a delay process it.
648 		 */
649 		if (nch == 0) {
650 			nch = getc(&tp->t_outq);
651 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
652 			tp->t_state |= TS_TIMEOUT;
653 			goto out;
654 		}
655 	}
656 	/*
657 	 * If characters to transmit, restart transmission.
658 	 */
659 	if (nch) {
660 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
661 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
662 		addr->dhulcr &= ~DHU_LC_TXABORT;
663 		addr->dhubcr = nch;
664 		addr->dhubar1 = car;
665 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
666 					DHU_BA2_DMAGO;
667 		tp->t_state |= TS_BUSY;
668 	}
669 out:
670 	splx(s);
671 }
672 
673 /*
674  * Stop output on a line, e.g. for ^S/^Q or output flush.
675  */
676 /*ARGSUSED*/
677 dhustop(tp, flag)
678 	register struct tty *tp;
679 {
680 	register struct dhudevice *addr;
681 	register int unit, s;
682 
683 	addr = (struct dhudevice *)tp->t_addr;
684 	/*
685 	 * Block input/output interrupts while messing with state.
686 	 */
687 	s = spl5();
688 	if (tp->t_state & TS_BUSY) {
689 		/*
690 		 * Device is transmitting; stop output
691 		 * by selecting the line and setting the
692 		 * abort xmit bit.  We will get an xmit interrupt,
693 		 * where we will figure out where to continue the
694 		 * next time the transmitter is enabled.  If
695 		 * TS_FLUSH is set, the outq will be flushed.
696 		 * In either case, dhustart will clear the TXABORT bit.
697 		 */
698 		unit = minor(tp->t_dev);
699 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
700 		addr->dhulcr |= DHU_LC_TXABORT;
701 		if ((tp->t_state&TS_TTSTOP)==0)
702 			tp->t_state |= TS_FLUSH;
703 	}
704 	(void) splx(s);
705 }
706 
707 /*
708  * DHU11 modem control
709  */
710 dhumctl(dev, bits, how)
711 	dev_t dev;
712 	int bits, how;
713 {
714 	register struct dhudevice *dhuaddr;
715 	register int unit, mbits;
716 	int s;
717 
718 	unit = UNIT(dev);
719 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
720 	unit &= 0xf;
721 	s = spl5();
722 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
723 	/*
724 	 * combine byte from stat register (read only, bits 16..23)
725 	 * with lcr register (read write, bits 0..15).
726 	 */
727 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
728 	switch (how) {
729 	case DMSET:
730 		mbits = (mbits & 0xff0000) | bits;
731 		break;
732 
733 	case DMBIS:
734 		mbits |= bits;
735 		break;
736 
737 	case DMBIC:
738 		mbits &= ~bits;
739 		break;
740 
741 	case DMGET:
742 		(void) splx(s);
743 		return(mbits);
744 	}
745 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
746 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
747 	(void) splx(s);
748 	return(mbits);
749 }
750 
751 /*
752  * Reset state of driver if UBA reset was necessary.
753  * Reset the line and modem control registers.
754  * restart transmitters.
755  */
756 dhureset(uban)
757 	int uban;
758 {
759 	register int dhu, unit;
760 	register struct tty *tp;
761 	register struct uba_device *ui;
762 	register struct dhudevice *addr;
763 	int i;
764 
765 	for (dhu = 0; dhu < NDHU; dhu++) {
766 		ui = dhuinfo[dhu];
767 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
768 			continue;
769 		printf(" dhu%d", dhu);
770 		if (dhu_uballoc[uban] == dhu) {
771 			int info;
772 
773 			info = uballoc(uban, (caddr_t)cfree,
774 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
775 			if (info)
776 				cbase[uban] = UBAI_ADDR(info);
777 			else {
778 				printf(" [can't get uba map]");
779 				cbase[uban] = -1;
780 			}
781 		}
782 		addr = (struct dhudevice *)ui->ui_addr;
783 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
784 		addr->dhutimo = DHU_DEF_TIMO;
785 		unit = dhu * 16;
786 		for (i = 0; i < 16; i++) {
787 			tp = &dhu_tty[unit];
788 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
789 				dhuparam(tp, &tp->t_termios);
790 				(void)dhumctl(unit, DHU_ON, DMSET);
791 				tp->t_state &= ~TS_BUSY;
792 				dhustart(tp);
793 			}
794 			unit++;
795 		}
796 	}
797 }
798 #endif
799