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