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