xref: /original-bsd/sys/vax/uba/dhu.c (revision 84689157)
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.8 (Berkeley) 02/08/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 "dir.h"
27 #include "user.h"
28 #include "proc.h"
29 #include "ioctl.h"
30 #include "tty.h"
31 #include "ttydefaults.h"
32 #include "map.h"
33 #include "buf.h"
34 #include "vm.h"
35 #include "kernel.h"
36 #include "syslog.h"
37 #include "tsleep.h"
38 
39 #include "uba.h"
40 #include "ubareg.h"
41 #include "ubavar.h"
42 #include "dhureg.h"
43 
44 #include "bkmac.h"
45 #include "clist.h"
46 #include "file.h"
47 #include "uio.h"
48 
49 /*
50  * Definition of the driver for the auto-configuration program.
51  */
52 int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
53 struct	uba_device *dhuinfo[NDHU];
54 u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
55 struct	uba_driver dhudriver =
56 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
57 
58 #define	NDHULINE 	(NDHU*16)
59 
60 #define	UNIT(x)	(minor(x))
61 
62 #ifndef PORTSELECTOR
63 #define SPEED	TTYDEF_SPEED
64 #define LFLAG	TTYDEF_LFLAG
65 #else
66 #define SPEED	B4800
67 #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
68 #endif
69 
70 /*
71  * default receive silo timeout value -- valid values are 2..255
72  * number of ms. to delay between first char received and receive interrupt
73  *
74  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
75  */
76 #define	DHU_DEF_TIMO	20
77 
78 /*
79  * Other values for silo timeout register defined here but not used:
80  * receive interrupt only on modem control or silo alarm (3/4 full)
81  */
82 #define DHU_POLL_TIMO	0
83 /*
84  * receive interrupt immediately on receive character
85  */
86 #define DHU_NO_TIMO	1
87 
88 /*
89  * Local variables for the driver
90  */
91 /*
92  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
93  *	EXTA => 19200 baud
94  *	EXTB => 2000 baud
95  */
96 struct speedtab dhuspeedtab[] = {
97 	19200,	14,
98 	9600,	13,
99 	4800,	11,
100 	2400,	10,
101 	2000,	9,
102 	1800,	8,
103 	1200,	7,
104 	600,	6,
105 	300,	5,
106 	150,	4,
107 	134,	3,
108 	110,	2,
109 	75,	1,
110 	0,	0,
111 	EXTA,	14,
112 	EXTB,	9,
113 	-1,	-1,
114 };
115 
116 short	dhusoftCAR[NDHU];
117 
118 struct	tty dhu_tty[NDHULINE];
119 int	ndhu = NDHULINE;
120 int	dhuact;				/* mask of active dhu's */
121 int	dhustart(), ttrstrt();
122 
123 /*
124  * The clist space is mapped by one terminal driver onto each UNIBUS.
125  * The identity of the board which allocated resources is recorded,
126  * so the process may be repeated after UNIBUS resets.
127  * The UBACVT macro converts a clist space address for unibus uban
128  * into an i/o space address for the DMA routine.
129  */
130 int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
131 int	cbase[NUBA];		/* base address of clists in unibus map */
132 #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
133 
134 /*
135  * Routine for configuration to force a dhu to interrupt.
136  */
137 /*ARGSUSED*/
138 dhuprobe(reg)
139 	caddr_t reg;
140 {
141 	register int br, cvec;		/* these are ``value-result'' */
142 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
143 	int i;
144 
145 #ifdef lint
146 	br = 0; cvec = br; br = cvec;
147 	if (ndhu == 0) ndhu = 1;
148 	dhurint(0); dhuxint(0);
149 #endif
150 	/*
151 	 * The basic idea here is:
152 	 *	do a self-test by setting the Master-Reset bit
153 	 *	if this fails, then return
154 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
155 	 *	therefore ask for a  Received-Data-Available interrupt
156 	 *	wait for it...
157 	 *	reset the interrupt-enable bit and flush out the diag. codes
158 	 */
159 	dhuaddr->dhucsr = DHU_CS_MCLR;
160 	for (i = 0; i < 1000; i++) {
161 		DELAY(10000);
162 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
163 			break;
164 	}
165 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
166 		return(0);
167 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
168 		return(0);
169 	dhuaddr->dhucsr = DHU_CS_RIE;
170 	DELAY(1000);
171 	dhuaddr->dhucsr = 0;
172 	while (dhuaddr->dhurbuf < 0)
173 		/* void */;
174 	return (sizeof(struct dhudevice));
175 }
176 
177 /*
178  * Routine called to attach a dhu.
179  */
180 dhuattach(ui)
181 	struct uba_device *ui;
182 {
183 
184 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
185 	cbase[ui->ui_ubanum] = -1;
186 	dhu_uballoc[ui->ui_ubanum] = -1;
187 }
188 
189 /*
190  * Open a DHU11 line, mapping the clist onto the uba if this
191  * is the first dhu on this uba.  Turn on this dhu if this is
192  * the first use of it.
193  */
194 /*ARGSUSED*/
195 dhuopen(dev, flag)
196 	dev_t dev;
197 {
198 	register struct tty *tp;
199 	register int unit, dhu;
200 	register struct dhudevice *addr;
201 	register struct uba_device *ui;
202 	int s;
203 	extern dhuparam();
204 
205 	unit = UNIT(dev);
206 	dhu = unit >> 4;
207 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
208 		return (ENXIO);
209 	tp = &dhu_tty[unit];
210 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
211 		return (EBUSY);
212 	addr = (struct dhudevice *)ui->ui_addr;
213 	tp->t_addr = (caddr_t)addr;
214 	tp->t_oproc = dhustart;
215 	tp->t_param = dhuparam;
216 	/*
217 	 * While setting up state for this uba and this dhu,
218 	 * block uba resets which can clear the state.
219 	 */
220 	s = spl5();
221 	if (cbase[ui->ui_ubanum] == -1) {
222 		dhu_uballoc[ui->ui_ubanum] = dhu;
223 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
224 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
225 	}
226 	if ((dhuact&(1<<dhu)) == 0) {
227 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
228 		addr->dhutimo = DHU_DEF_TIMO;
229 		dhuact |= (1<<dhu);
230 		/* anything else to configure whole board */
231 	}
232 	(void) splx(s);
233 	/*
234 	 * If this is first open, initialize tty state to default.
235 	 */
236 	if ((tp->t_state&TS_ISOPEN) == 0) {
237 		ttychars(tp);
238 #ifndef PORTSELECTOR
239 		if (tp->t_ospeed == 0) {
240 #endif
241 			tp->t_ispeed = SPEED;
242 			tp->t_ospeed = SPEED;
243 			ttsetwater(tp);
244 			tp->t_iflag = TTYDEF_IFLAG;
245 			tp->t_oflag = TTYDEF_OFLAG;
246 			tp->t_lflag = LFLAG;
247 			tp->t_cflag = TTYDEF_CFLAG;
248 #ifdef PORTSELECTOR
249 			tp->t_cflag |= HUPCL;
250 #else
251 		}
252 #endif
253 		tp->t_dev = dev;
254 		dhuparam(tp, &tp->t_termios);
255 	}
256 	/*
257 	 * Wait for carrier, then process line discipline specific open.
258 	 */
259 	s = spltty();
260 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
261 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
262 		tp->t_state |= TS_CARR_ON;
263 	while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
264 	       (tp->t_state & TS_CARR_ON) == 0) {
265 		tp->t_state |= TS_WOPEN;
266 		tsleep((caddr_t)&tp->t_rawq, TTIPRI, SLP_DHU_OPN, 0);
267 	}
268 	(void) splx(s);
269 	return ((*linesw[tp->t_line].l_open)(dev, tp));
270 }
271 
272 /*
273  * Close a DHU11 line, turning off the modem control.
274  */
275 /*ARGSUSED*/
276 dhuclose(dev, flag)
277 	dev_t dev;
278 	int flag;
279 {
280 	register struct tty *tp;
281 	register unit;
282 
283 	unit = UNIT(dev);
284 	tp = &dhu_tty[unit];
285 	(*linesw[tp->t_line].l_close)(tp);
286 	(void) dhumctl(unit, DHU_BRK, DMBIC);
287 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
288 	    (tp->t_state&TS_ISOPEN)==0)
289 #ifdef PORTSELECTOR
290 	{
291 		extern int wakeup();
292 
293 		(void) dhumctl(unit, DHU_OFF, DMSET);
294 		/* Hold DTR low for 0.5 seconds */
295 		timeout(wakeup, (caddr_t) &tp->t_dev, hz/2);
296 		sleep((caddr_t) &tp->t_dev, PZERO);
297 	}
298 #else
299 		(void) dhumctl(unit, DHU_OFF, DMSET);
300 #endif PORTSELECTOR
301 	ttyclose(tp);
302 }
303 
304 dhuread(dev, uio, flag)
305 	dev_t dev;
306 	struct uio *uio;
307 {
308 	register struct tty *tp = &dhu_tty[UNIT(dev)];
309 
310 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
311 }
312 
313 dhuwrite(dev, uio, flag)
314 	dev_t dev;
315 	struct uio *uio;
316 {
317 	register struct tty *tp = &dhu_tty[UNIT(dev)];
318 
319 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
320 }
321 
322 /*
323  * DHU11 receiver interrupt.
324  */
325 dhurint(dhu)
326 	int dhu;
327 {
328 	register struct tty *tp;
329 	register creg, c;
330 	register struct dhudevice *addr;
331 	register struct tty *tp0;
332 	register struct uba_device *ui;
333 	register line;
334 	int overrun = 0;
335 
336 #ifdef QBA
337 	(void) spltty();
338 #endif
339 	ui = dhuinfo[dhu];
340 	if (ui == 0 || ui->ui_alive == 0)
341 		return;
342 	addr = (struct dhudevice *)ui->ui_addr;
343 	tp0 = &dhu_tty[dhu<<4];
344 	/*
345 	 * Loop fetching characters from the silo for this
346 	 * dhu until there are no more in the silo.
347 	 */
348 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
349 		line = DHU_RX_LINE(creg);
350 		tp = tp0 + line;
351 		c = creg & 0xff;
352 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
353 			/*
354 			 * modem changed or diag info
355 			 */
356 			if (creg & DHU_RB_DIAG) {
357 				/* decode diagnostic messages */
358 				continue;
359 			}
360 			if (creg & DHU_ST_DCD)
361 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
362 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
363 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
364 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
365 			continue;
366 		}
367 		if ((tp->t_state&TS_ISOPEN) == 0) {
368 			wakeup((caddr_t)&tp->t_rawq);
369 #ifdef PORTSELECTOR
370 			if ((tp->t_state&TS_WOPEN) == 0)
371 #endif
372 				continue;
373 		}
374 		if (creg & DHU_RB_PE)
375 			c |= TTY_PE;
376 		if (creg & DHU_RB_DO && overrun == 0) {
377 			log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
378 			overrun = 1;
379 		}
380 		if (creg & DHU_RB_FE)
381 			c |= TTY_FE;
382 
383 		(*linesw[tp->t_line].l_rint)(c, tp);
384 	}
385 }
386 
387 /*
388  * Ioctl for DHU11.
389  */
390 /*ARGSUSED*/
391 dhuioctl(dev, cmd, data, flag)
392 	caddr_t data;
393 {
394 	register struct tty *tp;
395 	register int unit = UNIT(dev);
396 	int error;
397 
398 	tp = &dhu_tty[unit];
399 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
400 	if (error >= 0)
401 		return (error);
402 	error = ttioctl(tp, cmd, data, flag);
403 	if (error >= 0)
404 		return (error);
405 
406 	switch (cmd) {
407 	case TIOCSBRK:
408 		(void) dhumctl(unit, DHU_BRK, DMBIS);
409 		break;
410 
411 	case TIOCCBRK:
412 		(void) dhumctl(unit, DHU_BRK, DMBIC);
413 		break;
414 
415 	case TIOCSDTR:
416 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
417 		break;
418 
419 	case TIOCCDTR:
420 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
421 		break;
422 
423 	case TIOCMSET:
424 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
425 		break;
426 
427 	case TIOCMBIS:
428 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
429 		break;
430 
431 	case TIOCMBIC:
432 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
433 		break;
434 
435 	case TIOCMGET:
436 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
437 		break;
438 	default:
439 		return (ENOTTY);
440 	}
441 	return (0);
442 }
443 
444 dmtodhu(bits)
445 	register int bits;
446 {
447 	register int b = 0;
448 
449 	if (bits & DML_RTS) b |= DHU_RTS;
450 	if (bits & DML_DTR) b |= DHU_DTR;
451 	if (bits & DML_LE) b |= DHU_LE;
452 	return(b);
453 }
454 
455 dhutodm(bits)
456 	register int bits;
457 {
458 	register int b = 0;
459 
460 	if (bits & DHU_DSR) b |= DML_DSR;
461 	if (bits & DHU_RNG) b |= DML_RNG;
462 	if (bits & DHU_CAR) b |= DML_CAR;
463 	if (bits & DHU_CTS) b |= DML_CTS;
464 	if (bits & DHU_RTS) b |= DML_RTS;
465 	if (bits & DHU_DTR) b |= DML_DTR;
466 	if (bits & DHU_LE) b |= DML_LE;
467 	return(b);
468 }
469 
470 
471 /*
472  * Set parameters from open or stty into the DHU hardware
473  * registers.  Impossible values for speed or character
474  * size are ignored and not copied back into tp.
475  */
476 dhuparam(tp, want)
477 	register struct tty *tp;
478 	register struct termios *want;
479 {
480 	register int unit = UNIT(tp->t_dev);
481 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
482 	register int lpar;
483 	register long cflag;
484 	register int incode, outcode;
485 	int s;
486 
487 	/*
488 	 * Block interrupts so parameters will be set
489 	 * before the line interrupts.
490 	 */
491 	s = spltty();
492 
493 	if (want->c_ospeed == 0) {
494 		tp->t_ospeed = 0;
495 		tp->t_cflag |= HUPCL;
496 		(void)dhumctl(unit, DHU_OFF, DMSET);
497 		splx(s);
498 		return;
499 	}
500 
501 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
502 		tp->t_ospeed = want->c_ospeed;
503 	else
504 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
505 
506 	if (want->c_ispeed == 0) {
507 		tp->t_ispeed = 0;
508 		incode = outcode;
509 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
510 		tp->t_ispeed = want->c_ispeed;
511 	else
512 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
513 
514 	lpar = ((char)outcode<<12) | ((char)incode<<8);
515 
516 	switch (want->c_cflag&CSIZE) {
517 	case CS6: case CS7: case CS8:
518 		tp->t_cflag =  want->c_cflag;
519 		break;
520 	default:
521 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
522 	}
523 	cflag = tp->t_cflag;
524 
525 	switch(cflag&CSIZE) {
526 	case CS6:
527 		lpar |= DHU_LP_BITS6;
528 		break;
529 	case CS7:
530 		lpar |= DHU_LP_BITS7;
531 		break;
532 	case CS8:
533 		lpar |= DHU_LP_BITS8;
534 		break;
535 	}
536 	if (cflag&PARENB) {
537 		lpar |= DHU_LP_PENABLE;
538 		if ((cflag&PARODD) == 0)
539 			lpar |= DHU_LP_EPAR;
540 	}
541 	if (cflag&CSTOPB)
542 		lpar |= DHU_LP_TWOSB;
543 
544 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
545 	addr->dhulpr = lpar;
546 	splx(s);
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