xref: /csrg-svn/sys/vax/uba/dhu.c (revision 40729)
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.10 (Berkeley) 04/03/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 			break;
267 	}
268 	(void) splx(s);
269 	if (error)
270 		return (error);
271 	return ((*linesw[tp->t_line].l_open)(dev, tp));
272 }
273 
274 /*
275  * Close a DHU11 line, turning off the modem control.
276  */
277 /*ARGSUSED*/
278 dhuclose(dev, flag)
279 	dev_t dev;
280 	int flag;
281 {
282 	register struct tty *tp;
283 	register unit;
284 
285 	unit = UNIT(dev);
286 	tp = &dhu_tty[unit];
287 	(*linesw[tp->t_line].l_close)(tp);
288 	(void) dhumctl(unit, DHU_BRK, DMBIC);
289 	if ((tp->t_state&TS_WOPEN) || (tp->t_cflag&HUPCL) ||
290 	    (tp->t_state&TS_ISOPEN) == 0) {
291 #ifdef PORTSELECTOR
292 		(void) dhumctl(unit, DHU_OFF, DMSET);
293 		/* Hold DTR low for 0.5 seconds */
294 		(void) tsleep((caddr_t) &tp->t_dev, PZERO, ttclos, hz/2);
295 #else
296 		(void) dhumctl(unit, DHU_OFF, DMSET);
297 #endif PORTSELECTOR
298 	}
299 	return (ttyclose(tp));
300 }
301 
302 dhuread(dev, uio, flag)
303 	dev_t dev;
304 	struct uio *uio;
305 {
306 	register struct tty *tp = &dhu_tty[UNIT(dev)];
307 
308 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
309 }
310 
311 dhuwrite(dev, uio, flag)
312 	dev_t dev;
313 	struct uio *uio;
314 {
315 	register struct tty *tp = &dhu_tty[UNIT(dev)];
316 
317 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
318 }
319 
320 /*
321  * DHU11 receiver interrupt.
322  */
323 dhurint(dhu)
324 	int dhu;
325 {
326 	register struct tty *tp;
327 	register creg, c;
328 	register struct dhudevice *addr;
329 	register struct tty *tp0;
330 	register struct uba_device *ui;
331 	register line;
332 	int overrun = 0;
333 
334 #ifdef QBA
335 	(void) spltty();
336 #endif
337 	ui = dhuinfo[dhu];
338 	if (ui == 0 || ui->ui_alive == 0)
339 		return;
340 	addr = (struct dhudevice *)ui->ui_addr;
341 	tp0 = &dhu_tty[dhu<<4];
342 	/*
343 	 * Loop fetching characters from the silo for this
344 	 * dhu until there are no more in the silo.
345 	 */
346 	while ((creg = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
347 		line = DHU_RX_LINE(creg);
348 		tp = tp0 + line;
349 		c = creg & 0xff;
350 		if ((creg & DHU_RB_STAT) == DHU_RB_STAT) {
351 			/*
352 			 * modem changed or diag info
353 			 */
354 			if (creg & DHU_RB_DIAG) {
355 				/* decode diagnostic messages */
356 				continue;
357 			}
358 			if (creg & DHU_ST_DCD)
359 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
360 			else if ((dhusoftCAR[dhu] & (1<<line)) == 0 &&
361 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
362 				(void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET);
363 			continue;
364 		}
365 		if ((tp->t_state&TS_ISOPEN) == 0) {
366 			wakeup((caddr_t)&tp->t_rawq);
367 #ifdef PORTSELECTOR
368 			if ((tp->t_state&TS_WOPEN) == 0)
369 #endif
370 				continue;
371 		}
372 		if (creg & DHU_RB_PE)
373 			c |= TTY_PE;
374 		if (creg & DHU_RB_DO && overrun == 0) {
375 			log(LOG_WARNING, "dhu%d: silo overflow\n", dhu);
376 			overrun = 1;
377 		}
378 		if (creg & DHU_RB_FE)
379 			c |= TTY_FE;
380 
381 		(*linesw[tp->t_line].l_rint)(c, tp);
382 	}
383 }
384 
385 /*
386  * Ioctl for DHU11.
387  */
388 /*ARGSUSED*/
389 dhuioctl(dev, cmd, data, flag)
390 	caddr_t data;
391 {
392 	register struct tty *tp;
393 	register int unit = UNIT(dev);
394 	int error;
395 
396 	tp = &dhu_tty[unit];
397 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
398 	if (error >= 0)
399 		return (error);
400 	error = ttioctl(tp, cmd, data, flag);
401 	if (error >= 0)
402 		return (error);
403 
404 	switch (cmd) {
405 	case TIOCSBRK:
406 		(void) dhumctl(unit, DHU_BRK, DMBIS);
407 		break;
408 
409 	case TIOCCBRK:
410 		(void) dhumctl(unit, DHU_BRK, DMBIC);
411 		break;
412 
413 	case TIOCSDTR:
414 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
415 		break;
416 
417 	case TIOCCDTR:
418 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
419 		break;
420 
421 	case TIOCMSET:
422 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
423 		break;
424 
425 	case TIOCMBIS:
426 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
427 		break;
428 
429 	case TIOCMBIC:
430 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
431 		break;
432 
433 	case TIOCMGET:
434 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
435 		break;
436 	default:
437 		return (ENOTTY);
438 	}
439 	return (0);
440 }
441 
442 dmtodhu(bits)
443 	register int bits;
444 {
445 	register int b = 0;
446 
447 	if (bits & DML_RTS) b |= DHU_RTS;
448 	if (bits & DML_DTR) b |= DHU_DTR;
449 	if (bits & DML_LE) b |= DHU_LE;
450 	return(b);
451 }
452 
453 dhutodm(bits)
454 	register int bits;
455 {
456 	register int b = 0;
457 
458 	if (bits & DHU_DSR) b |= DML_DSR;
459 	if (bits & DHU_RNG) b |= DML_RNG;
460 	if (bits & DHU_CAR) b |= DML_CAR;
461 	if (bits & DHU_CTS) b |= DML_CTS;
462 	if (bits & DHU_RTS) b |= DML_RTS;
463 	if (bits & DHU_DTR) b |= DML_DTR;
464 	if (bits & DHU_LE) b |= DML_LE;
465 	return(b);
466 }
467 
468 
469 /*
470  * Set parameters from open or stty into the DHU hardware
471  * registers.  Impossible values for speed or character
472  * size are ignored and not copied back into tp.
473  */
474 dhuparam(tp, want)
475 	register struct tty *tp;
476 	register struct termios *want;
477 {
478 	register int unit = UNIT(tp->t_dev);
479 	register struct dhudevice *addr = (struct dhudevice *)tp->t_addr;
480 	register int lpar;
481 	register long cflag;
482 	register int incode, outcode;
483 	int s;
484 
485 	/*
486 	 * Block interrupts so parameters will be set
487 	 * before the line interrupts.
488 	 */
489 	s = spltty();
490 
491 	if (want->c_ospeed == 0) {
492 		tp->t_ospeed = 0;
493 		tp->t_cflag |= HUPCL;
494 		(void)dhumctl(unit, DHU_OFF, DMSET);
495 		splx(s);
496 		return;
497 	}
498 
499 	if ((outcode = ttspeedtab(want->c_ospeed, dhuspeedtab)) >= 0)
500 		tp->t_ospeed = want->c_ospeed;
501 	else
502 		outcode = ttspeedtab(tp->t_ospeed, dhuspeedtab);
503 
504 	if (want->c_ispeed == 0) {
505 		tp->t_ispeed = 0;
506 		incode = outcode;
507 	} else if ((incode = ttspeedtab(want->c_ispeed, dhuspeedtab)) >= 0)
508 		tp->t_ispeed = want->c_ispeed;
509 	else
510 		incode = ttspeedtab(tp->t_ispeed, dhuspeedtab);
511 
512 	lpar = ((char)outcode<<12) | ((char)incode<<8);
513 
514 	switch (want->c_cflag&CSIZE) {
515 	case CS6: case CS7: case CS8:
516 		tp->t_cflag =  want->c_cflag;
517 		break;
518 	default:
519 		tp->t_cflag = (tp->t_cflag&CSIZE) | (want->c_cflag & ~CSIZE);
520 	}
521 	cflag = tp->t_cflag;
522 
523 	switch(cflag&CSIZE) {
524 	case CS6:
525 		lpar |= DHU_LP_BITS6;
526 		break;
527 	case CS7:
528 		lpar |= DHU_LP_BITS7;
529 		break;
530 	case CS8:
531 		lpar |= DHU_LP_BITS8;
532 		break;
533 	}
534 	if (cflag&PARENB) {
535 		lpar |= DHU_LP_PENABLE;
536 		if ((cflag&PARODD) == 0)
537 			lpar |= DHU_LP_EPAR;
538 	}
539 	if (cflag&CSTOPB)
540 		lpar |= DHU_LP_TWOSB;
541 
542 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
543 	addr->dhulpr = lpar;
544 	splx(s);
545 }
546 
547 /*
548  * DHU11 transmitter interrupt.
549  * Restart each line which used to be active but has
550  * terminated transmission since the last interrupt.
551  */
552 dhuxint(dhu)
553 	int dhu;
554 {
555 	register struct tty *tp;
556 	register struct dhudevice *addr;
557 	register struct tty *tp0;
558 	register struct uba_device *ui;
559 	register int line, t;
560 	u_short cntr;
561 
562 #ifdef QBA
563 	(void) spl5();
564 #endif
565 	ui = dhuinfo[dhu];
566 	tp0 = &dhu_tty[dhu<<4];
567 	addr = (struct dhudevice *)ui->ui_addr;
568 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
569 		line = DHU_TX_LINE(t);
570 		tp = tp0 + line;
571 		tp->t_state &= ~TS_BUSY;
572 		if (t & DHU_CSH_NXM) {
573 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
574 			/* SHOULD RESTART OR SOMETHING... */
575 		}
576 		if (tp->t_state&TS_FLUSH)
577 			tp->t_state &= ~TS_FLUSH;
578 		else {
579 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
580 			/*
581 			 * Do arithmetic in a short to make up
582 			 * for lost 16&17 bits.
583 			 */
584 			cntr = addr->dhubar1 -
585 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
586 			ndflush(&tp->t_outq, (int)cntr);
587 		}
588 		if (tp->t_line)
589 			(*linesw[tp->t_line].l_start)(tp);
590 		else
591 			dhustart(tp);
592 	}
593 }
594 
595 /*
596  * Start (restart) transmission on the given DHU11 line.
597  */
598 dhustart(tp)
599 	register struct tty *tp;
600 {
601 	register struct dhudevice *addr;
602 	register int car, dhu, unit, nch;
603 	int s;
604 
605 	unit = minor(tp->t_dev);
606 	dhu = unit >> 4;
607 	unit &= 0xf;
608 	addr = (struct dhudevice *)tp->t_addr;
609 
610 	/*
611 	 * Must hold interrupts in following code to prevent
612 	 * state of the tp from changing.
613 	 */
614 	s = spl5();
615 	/*
616 	 * If it's currently active, or delaying, no need to do anything.
617 	 */
618 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
619 		goto out;
620 	/*
621 	 * If there are sleepers, and output has drained below low
622 	 * water mark, wake up the sleepers..
623 	 */
624 	if (tp->t_outq.c_cc <= tp->t_lowat) {
625 		if (tp->t_state&TS_ASLEEP) {
626 			tp->t_state &= ~TS_ASLEEP;
627 			wakeup((caddr_t)&tp->t_outq);
628 		}
629 		if (tp->t_wsel) {
630 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
631 			tp->t_wsel = 0;
632 			tp->t_state &= ~TS_WCOLL;
633 		}
634 	}
635 	/*
636 	 * Now restart transmission unless the output queue is
637 	 * empty.
638 	 */
639 	if (tp->t_outq.c_cc == 0)
640 		goto out;
641 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
642 		nch = ndqb(&tp->t_outq, 0);
643 	else {
644 		nch = ndqb(&tp->t_outq, 0200);
645 		/*
646 		 * If first thing on queue is a delay process it.
647 		 */
648 		if (nch == 0) {
649 			nch = getc(&tp->t_outq);
650 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
651 			tp->t_state |= TS_TIMEOUT;
652 			goto out;
653 		}
654 	}
655 	/*
656 	 * If characters to transmit, restart transmission.
657 	 */
658 	if (nch) {
659 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
660 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
661 		addr->dhulcr &= ~DHU_LC_TXABORT;
662 		addr->dhubcr = nch;
663 		addr->dhubar1 = car;
664 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
665 					DHU_BA2_DMAGO;
666 		tp->t_state |= TS_BUSY;
667 	}
668 out:
669 	splx(s);
670 }
671 
672 /*
673  * Stop output on a line, e.g. for ^S/^Q or output flush.
674  */
675 /*ARGSUSED*/
676 dhustop(tp, flag)
677 	register struct tty *tp;
678 {
679 	register struct dhudevice *addr;
680 	register int unit, s;
681 
682 	addr = (struct dhudevice *)tp->t_addr;
683 	/*
684 	 * Block input/output interrupts while messing with state.
685 	 */
686 	s = spl5();
687 	if (tp->t_state & TS_BUSY) {
688 		/*
689 		 * Device is transmitting; stop output
690 		 * by selecting the line and setting the
691 		 * abort xmit bit.  We will get an xmit interrupt,
692 		 * where we will figure out where to continue the
693 		 * next time the transmitter is enabled.  If
694 		 * TS_FLUSH is set, the outq will be flushed.
695 		 * In either case, dhustart will clear the TXABORT bit.
696 		 */
697 		unit = minor(tp->t_dev);
698 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
699 		addr->dhulcr |= DHU_LC_TXABORT;
700 		if ((tp->t_state&TS_TTSTOP)==0)
701 			tp->t_state |= TS_FLUSH;
702 	}
703 	(void) splx(s);
704 }
705 
706 /*
707  * DHU11 modem control
708  */
709 dhumctl(dev, bits, how)
710 	dev_t dev;
711 	int bits, how;
712 {
713 	register struct dhudevice *dhuaddr;
714 	register int unit, mbits;
715 	int s;
716 
717 	unit = UNIT(dev);
718 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
719 	unit &= 0xf;
720 	s = spl5();
721 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
722 	/*
723 	 * combine byte from stat register (read only, bits 16..23)
724 	 * with lcr register (read write, bits 0..15).
725 	 */
726 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
727 	switch (how) {
728 	case DMSET:
729 		mbits = (mbits & 0xff0000) | bits;
730 		break;
731 
732 	case DMBIS:
733 		mbits |= bits;
734 		break;
735 
736 	case DMBIC:
737 		mbits &= ~bits;
738 		break;
739 
740 	case DMGET:
741 		(void) splx(s);
742 		return(mbits);
743 	}
744 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
745 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
746 	(void) splx(s);
747 	return(mbits);
748 }
749 
750 /*
751  * Reset state of driver if UBA reset was necessary.
752  * Reset the line and modem control registers.
753  * restart transmitters.
754  */
755 dhureset(uban)
756 	int uban;
757 {
758 	register int dhu, unit;
759 	register struct tty *tp;
760 	register struct uba_device *ui;
761 	register struct dhudevice *addr;
762 	int i;
763 
764 	for (dhu = 0; dhu < NDHU; dhu++) {
765 		ui = dhuinfo[dhu];
766 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
767 			continue;
768 		printf(" dhu%d", dhu);
769 		if (dhu_uballoc[uban] == dhu) {
770 			int info;
771 
772 			info = uballoc(uban, (caddr_t)cfree,
773 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
774 			if (info)
775 				cbase[uban] = UBAI_ADDR(info);
776 			else {
777 				printf(" [can't get uba map]");
778 				cbase[uban] = -1;
779 			}
780 		}
781 		addr = (struct dhudevice *)ui->ui_addr;
782 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
783 		addr->dhutimo = DHU_DEF_TIMO;
784 		unit = dhu * 16;
785 		for (i = 0; i < 16; i++) {
786 			tp = &dhu_tty[unit];
787 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
788 				dhuparam(tp, &tp->t_termios);
789 				(void)dhumctl(unit, DHU_ON, DMSET);
790 				tp->t_state &= ~TS_BUSY;
791 				dhustart(tp);
792 			}
793 			unit++;
794 		}
795 	}
796 }
797 #endif
798