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