xref: /original-bsd/sys/vax/uba/dhu.c (revision de3f5c4e)
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.15 (Berkeley) 05/09/91
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 "../include/pte.h"
23 
24 #include "sys/param.h"
25 #include "sys/conf.h"
26 #include "sys/user.h"
27 #include "sys/proc.h"
28 #include "sys/ioctl.h"
29 #include "sys/tty.h"
30 #include "sys/ttydefaults.h"
31 #include "sys/map.h"
32 #include "sys/buf.h"
33 #include "sys/vm.h"
34 #include "sys/kernel.h"
35 #include "sys/syslog.h"
36 
37 #include "uba.h"
38 #include "ubareg.h"
39 #include "ubavar.h"
40 #include "dhureg.h"
41 
42 #include "sys/clist.h"
43 #include "sys/file.h"
44 #include "sys/uio.h"
45 
46 /*
47  * Definition of the driver for the auto-configuration program.
48  */
49 int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
50 struct	uba_device *dhuinfo[NDHU];
51 u_short dhustd[] = { 160440, 160500, 0 };	/* some common addresses */
52 struct	uba_driver dhudriver =
53 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
54 
55 #define	NDHULINE 	(NDHU*16)
56 
57 #define	UNIT(x)	(minor(x))
58 
59 #ifndef PORTSELECTOR
60 #define SPEED	TTYDEF_SPEED
61 #define LFLAG	TTYDEF_LFLAG
62 #else
63 #define SPEED	B4800
64 #define LFLAG	(TTYDEF_LFLAG & ~ECHO)
65 #endif
66 
67 /*
68  * default receive silo timeout value -- valid values are 2..255
69  * number of ms. to delay between first char received and receive interrupt
70  *
71  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
72  */
73 #define	DHU_DEF_TIMO	20
74 
75 /*
76  * Other values for silo timeout register defined here but not used:
77  * receive interrupt only on modem control or silo alarm (3/4 full)
78  */
79 #define DHU_POLL_TIMO	0
80 /*
81  * receive interrupt immediately on receive character
82  */
83 #define DHU_NO_TIMO	1
84 
85 /*
86  * Local variables for the driver
87  */
88 /*
89  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
90  *	EXTA => 19200 baud
91  *	EXTB => 2000 baud
92  */
93 struct speedtab dhuspeedtab[] = {
94 	19200,	14,
95 	9600,	13,
96 	4800,	11,
97 	2400,	10,
98 	2000,	9,
99 	1800,	8,
100 	1200,	7,
101 	600,	6,
102 	300,	5,
103 	150,	4,
104 	134,	3,
105 	110,	2,
106 	75,	1,
107 	0,	0,
108 	EXTA,	14,
109 	EXTB,	9,
110 	-1,	-1,
111 };
112 
113 short	dhusoftCAR[NDHU];
114 
115 struct	tty dhu_tty[NDHULINE];
116 int	ndhu = NDHULINE;
117 int	dhuact;				/* mask of active dhu's */
118 int	dhustart(), ttrstrt();
119 
120 /*
121  * The clist space is mapped by one terminal driver onto each UNIBUS.
122  * The identity of the board which allocated resources is recorded,
123  * so the process may be repeated after UNIBUS resets.
124  * The UBACVT macro converts a clist space address for unibus uban
125  * into an i/o space address for the DMA routine.
126  */
127 int	dhu_uballoc[NUBA];	/* which dhu (if any) allocated unibus map */
128 int	cbase[NUBA];		/* base address of clists in unibus map */
129 #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
130 
131 /*
132  * Routine for configuration to force a dhu to interrupt.
133  */
134 /*ARGSUSED*/
135 dhuprobe(reg)
136 	caddr_t reg;
137 {
138 	register int br, cvec;		/* these are ``value-result'' */
139 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
140 	int i;
141 
142 #ifdef lint
143 	br = 0; cvec = br; br = cvec;
144 	if (ndhu == 0) ndhu = 1;
145 	dhurint(0); dhuxint(0);
146 #endif
147 	/*
148 	 * The basic idea here is:
149 	 *	do a self-test by setting the Master-Reset bit
150 	 *	if this fails, then return
151 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
152 	 *	therefore ask for a  Received-Data-Available interrupt
153 	 *	wait for it...
154 	 *	reset the interrupt-enable bit and flush out the diag. codes
155 	 */
156 	dhuaddr->dhucsr = DHU_CS_MCLR;
157 	for (i = 0; i < 1000; i++) {
158 		DELAY(10000);
159 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
160 			break;
161 	}
162 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
163 		return(0);
164 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
165 		return(0);
166 	dhuaddr->dhucsr = DHU_CS_RIE;
167 	DELAY(1000);
168 	dhuaddr->dhucsr = 0;
169 	while (dhuaddr->dhurbuf < 0)
170 		/* void */;
171 	return (sizeof(struct dhudevice));
172 }
173 
174 /*
175  * Routine called to attach a dhu.
176  */
177 dhuattach(ui)
178 	struct uba_device *ui;
179 {
180 
181 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
182 	cbase[ui->ui_ubanum] = -1;
183 	dhu_uballoc[ui->ui_ubanum] = -1;
184 }
185 
186 /*
187  * Open a DHU11 line, mapping the clist onto the uba if this
188  * is the first dhu on this uba.  Turn on this dhu if this is
189  * the first use of it.
190  */
191 /*ARGSUSED*/
192 dhuopen(dev, flag)
193 	dev_t dev;
194 {
195 	register struct tty *tp;
196 	register int unit, dhu;
197 	register struct dhudevice *addr;
198 	register struct uba_device *ui;
199 	int s, error = 0;
200 	extern dhuparam();
201 
202 	unit = UNIT(dev);
203 	dhu = unit >> 4;
204 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
205 		return (ENXIO);
206 	tp = &dhu_tty[unit];
207 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
208 		return (EBUSY);
209 	addr = (struct dhudevice *)ui->ui_addr;
210 	tp->t_addr = (caddr_t)addr;
211 	tp->t_oproc = dhustart;
212 	tp->t_param = dhuparam;
213 	/*
214 	 * While setting up state for this uba and this dhu,
215 	 * block uba resets which can clear the state.
216 	 */
217 	s = spl5();
218 	if (cbase[ui->ui_ubanum] == -1) {
219 		dhu_uballoc[ui->ui_ubanum] = dhu;
220 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
221 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
222 	}
223 	if ((dhuact&(1<<dhu)) == 0) {
224 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
225 		addr->dhutimo = DHU_DEF_TIMO;
226 		dhuact |= (1<<dhu);
227 		/* anything else to configure whole board */
228 	}
229 	(void) splx(s);
230 	/*
231 	 * If this is first open, initialize tty state to default.
232 	 */
233 	if ((tp->t_state&TS_ISOPEN) == 0) {
234 		tp->t_state |= TS_WOPEN;
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 = ttysleep(tp, (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 (0);
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 	return (0);
546 }
547 
548 /*
549  * DHU11 transmitter interrupt.
550  * Restart each line which used to be active but has
551  * terminated transmission since the last interrupt.
552  */
553 dhuxint(dhu)
554 	int dhu;
555 {
556 	register struct tty *tp;
557 	register struct dhudevice *addr;
558 	register struct tty *tp0;
559 	register struct uba_device *ui;
560 	register int line, t;
561 	u_short cntr;
562 
563 #ifdef QBA
564 	(void) spl5();
565 #endif
566 	ui = dhuinfo[dhu];
567 	tp0 = &dhu_tty[dhu<<4];
568 	addr = (struct dhudevice *)ui->ui_addr;
569 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
570 		line = DHU_TX_LINE(t);
571 		tp = tp0 + line;
572 		tp->t_state &= ~TS_BUSY;
573 		if (t & DHU_CSH_NXM) {
574 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
575 			/* SHOULD RESTART OR SOMETHING... */
576 		}
577 		if (tp->t_state&TS_FLUSH)
578 			tp->t_state &= ~TS_FLUSH;
579 		else {
580 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
581 			/*
582 			 * Do arithmetic in a short to make up
583 			 * for lost 16&17 bits.
584 			 */
585 			cntr = addr->dhubar1 -
586 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
587 			ndflush(&tp->t_outq, (int)cntr);
588 		}
589 		if (tp->t_line)
590 			(*linesw[tp->t_line].l_start)(tp);
591 		else
592 			dhustart(tp);
593 	}
594 }
595 
596 /*
597  * Start (restart) transmission on the given DHU11 line.
598  */
599 dhustart(tp)
600 	register struct tty *tp;
601 {
602 	register struct dhudevice *addr;
603 	register int car, dhu, unit, nch;
604 	int s;
605 
606 	unit = minor(tp->t_dev);
607 	dhu = unit >> 4;
608 	unit &= 0xf;
609 	addr = (struct dhudevice *)tp->t_addr;
610 
611 	/*
612 	 * Must hold interrupts in following code to prevent
613 	 * state of the tp from changing.
614 	 */
615 	s = spl5();
616 	/*
617 	 * If it's currently active, or delaying, no need to do anything.
618 	 */
619 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
620 		goto out;
621 	/*
622 	 * If there are sleepers, and output has drained below low
623 	 * water mark, wake up the sleepers..
624 	 */
625 	if (tp->t_outq.c_cc <= tp->t_lowat) {
626 		if (tp->t_state&TS_ASLEEP) {
627 			tp->t_state &= ~TS_ASLEEP;
628 			wakeup((caddr_t)&tp->t_outq);
629 		}
630 		if (tp->t_wsel) {
631 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
632 			tp->t_wsel = 0;
633 			tp->t_state &= ~TS_WCOLL;
634 		}
635 	}
636 	/*
637 	 * Now restart transmission unless the output queue is
638 	 * empty.
639 	 */
640 	if (tp->t_outq.c_cc == 0)
641 		goto out;
642 	if (1 || !(tp->t_oflag & OPOST))	/*XXX*/
643 		nch = ndqb(&tp->t_outq, 0);
644 	else {
645 		nch = ndqb(&tp->t_outq, 0200);
646 		/*
647 		 * If first thing on queue is a delay process it.
648 		 */
649 		if (nch == 0) {
650 			nch = getc(&tp->t_outq);
651 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
652 			tp->t_state |= TS_TIMEOUT;
653 			goto out;
654 		}
655 	}
656 	/*
657 	 * If characters to transmit, restart transmission.
658 	 */
659 	if (nch) {
660 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
661 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
662 		addr->dhulcr &= ~DHU_LC_TXABORT;
663 		addr->dhubcr = nch;
664 		addr->dhubar1 = car;
665 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
666 					DHU_BA2_DMAGO;
667 		tp->t_state |= TS_BUSY;
668 	}
669 out:
670 	splx(s);
671 }
672 
673 /*
674  * Stop output on a line, e.g. for ^S/^Q or output flush.
675  */
676 /*ARGSUSED*/
677 dhustop(tp, flag)
678 	register struct tty *tp;
679 {
680 	register struct dhudevice *addr;
681 	register int unit, s;
682 
683 	addr = (struct dhudevice *)tp->t_addr;
684 	/*
685 	 * Block input/output interrupts while messing with state.
686 	 */
687 	s = spl5();
688 	if (tp->t_state & TS_BUSY) {
689 		/*
690 		 * Device is transmitting; stop output
691 		 * by selecting the line and setting the
692 		 * abort xmit bit.  We will get an xmit interrupt,
693 		 * where we will figure out where to continue the
694 		 * next time the transmitter is enabled.  If
695 		 * TS_FLUSH is set, the outq will be flushed.
696 		 * In either case, dhustart will clear the TXABORT bit.
697 		 */
698 		unit = minor(tp->t_dev);
699 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
700 		addr->dhulcr |= DHU_LC_TXABORT;
701 		if ((tp->t_state&TS_TTSTOP)==0)
702 			tp->t_state |= TS_FLUSH;
703 	}
704 	(void) splx(s);
705 }
706 
707 /*
708  * DHU11 modem control
709  */
710 dhumctl(dev, bits, how)
711 	dev_t dev;
712 	int bits, how;
713 {
714 	register struct dhudevice *dhuaddr;
715 	register int unit, mbits;
716 	int s;
717 
718 	unit = UNIT(dev);
719 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
720 	unit &= 0xf;
721 	s = spl5();
722 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
723 	/*
724 	 * combine byte from stat register (read only, bits 16..23)
725 	 * with lcr register (read write, bits 0..15).
726 	 */
727 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
728 	switch (how) {
729 	case DMSET:
730 		mbits = (mbits & 0xff0000) | bits;
731 		break;
732 
733 	case DMBIS:
734 		mbits |= bits;
735 		break;
736 
737 	case DMBIC:
738 		mbits &= ~bits;
739 		break;
740 
741 	case DMGET:
742 		(void) splx(s);
743 		return(mbits);
744 	}
745 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
746 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
747 	(void) splx(s);
748 	return(mbits);
749 }
750 
751 /*
752  * Reset state of driver if UBA reset was necessary.
753  * Reset the line and modem control registers.
754  * restart transmitters.
755  */
756 dhureset(uban)
757 	int uban;
758 {
759 	register int dhu, unit;
760 	register struct tty *tp;
761 	register struct uba_device *ui;
762 	register struct dhudevice *addr;
763 	int i;
764 
765 	for (dhu = 0; dhu < NDHU; dhu++) {
766 		ui = dhuinfo[dhu];
767 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
768 			continue;
769 		printf(" dhu%d", dhu);
770 		if (dhu_uballoc[uban] == dhu) {
771 			int info;
772 
773 			info = uballoc(uban, (caddr_t)cfree,
774 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
775 			if (info)
776 				cbase[uban] = UBAI_ADDR(info);
777 			else {
778 				printf(" [can't get uba map]");
779 				cbase[uban] = -1;
780 			}
781 		}
782 		addr = (struct dhudevice *)ui->ui_addr;
783 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
784 		addr->dhutimo = DHU_DEF_TIMO;
785 		unit = dhu * 16;
786 		for (i = 0; i < 16; i++) {
787 			tp = &dhu_tty[unit];
788 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
789 				dhuparam(tp, &tp->t_termios);
790 				(void)dhumctl(unit, DHU_ON, DMSET);
791 				tp->t_state &= ~TS_BUSY;
792 				dhustart(tp);
793 			}
794 			unit++;
795 		}
796 	}
797 }
798 #endif
799