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