xref: /original-bsd/sys/vax/uba/dh.c (revision 6884d44a)
1 /*
2  * Copyright (c) 1982, 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  *	@(#)dh.c	7.15 (Berkeley) 12/16/90
7  */
8 
9 #include "dh.h"
10 #if NDH > 0
11 /*
12  * DH-11/DM-11 driver
13  */
14 #include "../include/pte.h"
15 
16 #include "sys/param.h"
17 #include "uba.h"
18 #include "sys/conf.h"
19 #include "sys/user.h"
20 #include "sys/proc.h"
21 #include "sys/ioctl.h"
22 #include "sys/tty.h"
23 #include "sys/map.h"
24 #include "sys/buf.h"
25 #include "sys/vm.h"
26 #include "sys/kernel.h"
27 #include "sys/syslog.h"
28 
29 #include "ubareg.h"
30 #include "ubavar.h"
31 #include "dhreg.h"
32 #include "dmreg.h"
33 
34 #include "sys/bkmac.h"
35 #include "sys/clist.h"
36 #include "sys/file.h"
37 #include "sys/uio.h"
38 
39 /*
40  * Definition of the driver for the auto-configuration program.
41  * There is one definition for the dh and one for the dm.
42  */
43 int	dhprobe(), dhattach(), dhrint(), dhxint(), dhtimer();
44 struct	uba_device *dhinfo[NDH];
45 u_short	dhstd[] = { 0 };
46 struct	uba_driver dhdriver =
47 	{ dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo };
48 
49 int	dmprobe(), dmattach(), dmintr();
50 struct	uba_device *dminfo[NDH];
51 u_short	dmstd[] = { 0 };
52 struct	uba_driver dmdriver =
53 	{ dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo };
54 
55 #ifndef	PORTSELECTOR
56 #define	ISPEED	TTYDEF_SPEED
57 #define	LFLAG	TTYDEF_LFLAG
58 #else
59 #define	ISPEED	B4800
60 #define	LFLAG	(TTYDEF_LFLAG&~ECHO)
61 #endif
62 
63 #define	FASTTIMER	(hz/30)		/* scan rate with silos on */
64 
65 /*
66  * Local variables for the driver
67  */
68 short	dhsar[NDH];			/* software copy of last bar */
69 short	dhsoftCAR[NDH];
70 
71 struct	tty dh11[NDH*16];
72 int	ndh11	= NDH*16;
73 int	dhact;				/* mask of active dh's */
74 int	dhsilos;			/* mask of dh's with silo in use */
75 int	dhchars[NDH];			/* recent input count */
76 int	dhrate[NDH];			/* smoothed input count */
77 int	dhhighrate = 100;		/* silo on if dhchars > dhhighrate */
78 int	dhlowrate = 75;			/* silo off if dhrate < dhlowrate */
79 static short timerstarted;
80 int	dhstart(), ttrstrt();
81 
82 struct speedtab dhspeedtab[] = {
83 	19200,	14,
84 	9600,	13,
85 	4800,	12,
86 	2400,	11,
87 	1800,	10,
88 	1200,	9,
89 	600,	8,
90 	300,	7,
91 	200,	6,
92 	150,	5,
93 	134,	4,
94 	110,	3,
95 	75,	2,
96 	50,	1,
97 	0,	0,
98 	EXTA,	14,
99 	EXTB,	15,
100 	-1,	-1
101 };
102 
103 /*
104  * The clist space is mapped by one terminal driver onto each UNIBUS.
105  * The identity of the board which allocated resources is recorded,
106  * so the process may be repeated after UNIBUS resets.
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	dh_uballoc[NUBA];	/* which dh (if any) allocated unibus map */
111 int	cbase[NUBA];		/* base address of clists in unibus map */
112 #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
113 
114 /*
115  * Routine for configuration to force a dh to interrupt.
116  * Set to transmit at 9600 baud, and cause a transmitter interrupt.
117  */
118 /*ARGSUSED*/
119 dhprobe(reg)
120 	caddr_t reg;
121 {
122 	register int br, cvec;		/* these are ``value-result'' */
123 	register struct dhdevice *dhaddr = (struct dhdevice *)reg;
124 
125 #ifdef lint
126 	br = 0; cvec = br; br = cvec;
127 	if (ndh11 == 0) ndh11 = 1;
128 	dhrint(0); dhxint(0);
129 #endif
130 #ifndef notdef
131 	dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI;
132 	DELAY(1000);
133 	dhaddr->un.dhcsr &= ~DH_RI;
134 	dhaddr->un.dhcsr = 0;
135 #else
136 	dhaddr->un.dhcsr = DH_TIE;
137 	DELAY(5);
138 	dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE;
139 	dhaddr->dhbcr = -1;
140 	dhaddr->dhcar = 0;
141 	dhaddr->dhbar = 1;
142 	DELAY(100000);		/* wait 1/10'th of a sec for interrupt */
143 	dhaddr->un.dhcsr = 0;
144 	if (cvec && cvec != 0x200)
145 		cvec -= 4;		/* transmit -> receive */
146 #endif
147 	return (sizeof (struct dhdevice));
148 }
149 
150 /*
151  * Routine called to attach a dh.
152  */
153 dhattach(ui)
154 	struct uba_device *ui;
155 {
156 
157 	dhsoftCAR[ui->ui_unit] = ui->ui_flags;
158 	cbase[ui->ui_ubanum] = -1;
159 	dh_uballoc[ui->ui_ubanum] = -1;
160 }
161 
162 /*
163  * Configuration routine to cause a dm to interrupt.
164  */
165 dmprobe(reg)
166 	caddr_t reg;
167 {
168 	register int br, vec;			/* value-result */
169 	register struct dmdevice *dmaddr = (struct dmdevice *)reg;
170 
171 #ifdef lint
172 	br = 0; vec = br; br = vec;
173 	dmintr(0);
174 #endif
175 	dmaddr->dmcsr = DM_DONE|DM_IE;
176 	DELAY(20);
177 	dmaddr->dmcsr = 0;
178 	return (1);
179 }
180 
181 /*ARGSUSED*/
182 dmattach(ui)
183 	struct uba_device *ui;
184 {
185 
186 	/* no local state to set up */
187 }
188 
189 /*
190  * Open a DH11 line, mapping the clist onto the uba if this
191  * is the first dh on this uba.  Turn on this dh if this is
192  * the first use of it.  Also do a dmopen to wait for carrier.
193  */
194 /*ARGSUSED*/
195 dhopen(dev, flag)
196 	dev_t dev;
197 {
198 	register struct tty *tp;
199 	register int unit, dh;
200 	register struct dhdevice *addr;
201 	register struct uba_device *ui;
202 	int s, error;
203 	int dhparam();
204 
205 	unit = minor(dev);
206 	dh = unit >> 4;
207 	if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0)
208 		return (ENXIO);
209 	tp = &dh11[unit];
210 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
211 		return (EBUSY);
212 	addr = (struct dhdevice *)ui->ui_addr;
213 	tp->t_addr = (caddr_t)addr;
214 	tp->t_oproc = dhstart;
215 	tp->t_param = dhparam;
216 	tp->t_dev = dev;
217 	/*
218 	 * While setting up state for this uba and this dh,
219 	 * block uba resets which can clear the state.
220 	 */
221 	s = spl5();
222 	if (cbase[ui->ui_ubanum] == -1) {
223 		dh_uballoc[ui->ui_ubanum] = dh;
224 		cbase[ui->ui_ubanum] = UBAI_ADDR(uballoc(ui->ui_ubanum,
225 		    (caddr_t)cfree, nclist*sizeof(struct cblock), 0));
226 	}
227 	if (timerstarted == 0) {
228 		timerstarted++;
229 		timeout(dhtimer, (caddr_t) 0, hz);
230 	}
231 	if ((dhact&(1<<dh)) == 0) {
232 		addr->un.dhcsr |= DH_IE;
233 		dhact |= (1<<dh);
234 		addr->dhsilo = 0;
235 	}
236 	splx(s);
237 	/*
238 	 * If this is first open, initialize tty state to default.
239 	 */
240 	if ((tp->t_state&TS_ISOPEN) == 0) {
241 		tp->t_state |= TS_WOPEN;
242 		ttychars(tp);
243 #ifndef PORTSELECTOR
244 		if (tp->t_ispeed == 0) {
245 #endif
246 			tp->t_iflag = TTYDEF_IFLAG;
247 			tp->t_oflag = TTYDEF_OFLAG;
248 			tp->t_cflag = TTYDEF_CFLAG;
249 			tp->t_lflag = LFLAG;
250 			tp->t_ispeed = tp->t_ospeed = ISPEED;
251 #ifdef PORTSELECTOR
252 			tp->t_cflag |= HUPCL;
253 #else
254 		}
255 #endif
256 		dhparam(tp, &tp->t_termios);
257 		ttsetwater(tp);
258 	}
259 	/*
260 	 * Wait for carrier, then process line discipline specific open.
261 	 */
262 	if (error = dmopen(dev, flag))
263 		return (error);
264 	return ((*linesw[tp->t_line].l_open)(dev, tp));
265 }
266 
267 /*
268  * Close a DH11 line, turning off the DM11.
269  */
270 /*ARGSUSED*/
271 dhclose(dev, flag)
272 	dev_t dev;
273 	int flag;
274 {
275 	register struct tty *tp;
276 	register unit;
277 
278 	unit = minor(dev);
279 	tp = &dh11[unit];
280 	(*linesw[tp->t_line].l_close)(tp);
281 	((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
282 	if (tp->t_cflag&HUPCL || (tp->t_state&TS_ISOPEN)==0)
283 		dmctl(unit, DML_OFF, DMSET);
284 	return (ttyclose(tp));
285 }
286 
287 dhread(dev, uio, flag)
288 	dev_t dev;
289 	struct uio *uio;
290 {
291 	register struct tty *tp = &dh11[minor(dev)];
292 
293 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
294 }
295 
296 dhwrite(dev, uio, flag)
297 	dev_t dev;
298 	struct uio *uio;
299 {
300 	register struct tty *tp = &dh11[minor(dev)];
301 
302 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
303 }
304 
305 /*
306  * DH11 receiver interrupt.
307  */
308 dhrint(dh)
309 	int dh;
310 {
311 	register struct tty *tp;
312 	register c, cc;
313 	register struct dhdevice *addr;
314 	register struct tty *tp0;
315 	register struct uba_device *ui;
316 	int overrun = 0;
317 
318 	ui = dhinfo[dh];
319 	if (ui == 0 || ui->ui_alive == 0)
320 		return;
321 	addr = (struct dhdevice *)ui->ui_addr;
322 	tp0 = &dh11[dh<<4];
323 	/*
324 	 * Loop fetching characters from the silo for this
325 	 * dh until there are no more in the silo.
326 	 */
327 	while ((c = addr->dhrcr) < 0) {
328 		tp = tp0 + ((c>>8)&0xf);
329 		dhchars[dh]++;
330 		if ((tp->t_state&TS_ISOPEN)==0) {
331 			wakeup((caddr_t)&tp->t_rawq);
332 #ifdef PORTSELECTOR
333 			if ((tp->t_state&TS_WOPEN) == 0)
334 #endif
335 				continue;
336 		}
337 		cc = c&0xff;
338 		if (c&DH_PE)
339 			cc |= TTY_PE;
340 		if ((c&DH_DO) && overrun == 0) {
341 			log(LOG_WARNING, "dh%d: silo overflow\n", dh);
342 			overrun = 1;
343 		}
344 		if (c&DH_FE)
345 			cc |= TTY_FE;
346 		(*linesw[tp->t_line].l_rint)(cc, tp);
347 	}
348 }
349 
350 /*
351  * Ioctl for DH11.
352  */
353 /*ARGSUSED*/
354 dhioctl(dev, cmd, data, flag)
355 	caddr_t data;
356 {
357 	register struct tty *tp;
358 	register int unit = minor(dev);
359 	int error;
360 
361 	tp = &dh11[unit];
362 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
363 	if (error >= 0)
364 		return (error);
365 	error = ttioctl(tp, cmd, data, flag);
366 	if (error >= 0)
367 		return (error);
368 	switch (cmd) {
369 
370 	case TIOCSBRK:
371 		((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017);
372 		break;
373 
374 	case TIOCCBRK:
375 		((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017));
376 		break;
377 
378 	case TIOCSDTR:
379 		dmctl(unit, DML_DTR|DML_RTS, DMBIS);
380 		break;
381 
382 	case TIOCCDTR:
383 		dmctl(unit, DML_DTR|DML_RTS, DMBIC);
384 		break;
385 
386 	default:
387 		return (ENOTTY);
388 	}
389 	return (0);
390 }
391 
392 /*
393  * Set parameters from open or stty into the DH hardware
394  * registers.
395  */
396 dhparam(tp, t)
397 	register struct tty *tp;
398 	register struct termios *t;
399 {
400 	register struct dhdevice *addr;
401 	register int lpar;
402 	register int cflag = t->c_cflag;
403 	int unit = minor(tp->t_dev);
404 	int s;
405 	int ispeed = ttspeedtab(t->c_ispeed, dhspeedtab);
406 	int ospeed = ttspeedtab(t->c_ospeed, dhspeedtab);
407 
408 	/* check requested parameters */
409 	if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
410 		return(EINVAL);
411 	if (ispeed == 0)
412 		ispeed = ospeed;
413 	/* and copy to tty */
414 	tp->t_ispeed = t->c_ispeed;
415 	tp->t_ospeed = t->c_ospeed;
416 	tp->t_cflag = cflag;
417 	/*
418 	 * Block interrupts so parameters will be set
419 	 * before the line interrupts.
420 	 */
421 	addr = (struct dhdevice *)tp->t_addr;
422 	s = spl5();
423 	addr->un.dhcsrl = (unit&0xf) | DH_IE;
424 	if (ospeed == 0) {
425 		tp->t_cflag |= HUPCL;
426 		dmctl(unit, DML_OFF, DMSET);
427 		splx(s);
428 		return 0;
429 	}
430 	lpar = (ospeed<<10) | (ispeed<<6);
431 	switch (cflag&CSIZE) {
432 	case CS6:	lpar |= BITS6; break;
433 	case CS7:	lpar |= BITS7; break;
434 	case CS8:	lpar |= BITS8; break;
435 	}
436 	if (cflag&PARENB)
437 		lpar |= PENABLE;
438 	if (cflag&PARODD)
439 		lpar |= OPAR;
440 	if (cflag&CSTOPB)
441 		lpar |= TWOSB;
442 	addr->dhlpr = lpar;
443 	splx(s);
444 	return 0;
445 }
446 
447 /*
448  * DH11 transmitter interrupt.
449  * Restart each line which used to be active but has
450  * terminated transmission since the last interrupt.
451  */
452 dhxint(dh)
453 	int dh;
454 {
455 	register struct tty *tp;
456 	register struct dhdevice *addr;
457 	short ttybit, bar, *sbar;
458 	register struct uba_device *ui;
459 	register int unit;
460 	u_short cntr;
461 
462 	ui = dhinfo[dh];
463 	addr = (struct dhdevice *)ui->ui_addr;
464 	if (addr->un.dhcsr & DH_NXM) {
465 		addr->un.dhcsr |= DH_CNI;
466 		printf("dh%d: NXM\n", dh);
467 	}
468 	sbar = &dhsar[dh];
469 	bar = *sbar & ~addr->dhbar;
470 	unit = dh * 16; ttybit = 1;
471 	addr->un.dhcsr &= (short)~DH_TI;
472 	for (; bar; unit++, ttybit <<= 1) {
473 		if (bar & ttybit) {
474 			*sbar &= ~ttybit;
475 			bar &= ~ttybit;
476 			tp = &dh11[unit];
477 			tp->t_state &= ~TS_BUSY;
478 			if (tp->t_state&TS_FLUSH)
479 				tp->t_state &= ~TS_FLUSH;
480 			else {
481 				addr->un.dhcsrl = (unit&017)|DH_IE;
482 				/*
483 				 * Do arithmetic in a short to make up
484 				 * for lost 16&17 bits.
485 				 */
486 				cntr = addr->dhcar -
487 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
488 				ndflush(&tp->t_outq, (int)cntr);
489 			}
490 			if (tp->t_line)
491 				(*linesw[tp->t_line].l_start)(tp);
492 			else
493 				dhstart(tp);
494 		}
495 	}
496 }
497 
498 /*
499  * Start (restart) transmission on the given DH11 line.
500  */
501 dhstart(tp)
502 	register struct tty *tp;
503 {
504 	register struct dhdevice *addr;
505 	register int car, dh, unit, nch;
506 	int s;
507 
508 	unit = minor(tp->t_dev);
509 	dh = unit >> 4;
510 	unit &= 0xf;
511 	addr = (struct dhdevice *)tp->t_addr;
512 
513 	/*
514 	 * Must hold interrupts in following code to prevent
515 	 * state of the tp from changing.
516 	 */
517 	s = spl5();
518 	/*
519 	 * If it's currently active, or delaying, no need to do anything.
520 	 */
521 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
522 		goto out;
523 	/*
524 	 * If there are sleepers, and output has drained below low
525 	 * water mark, wake up the sleepers.
526 	 */
527 	if (tp->t_outq.c_cc<=tp->t_lowat) {
528 		if (tp->t_state&TS_ASLEEP) {
529 			tp->t_state &= ~TS_ASLEEP;
530 			wakeup((caddr_t)&tp->t_outq);
531 		}
532 		if (tp->t_wsel) {
533 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
534 			tp->t_wsel = 0;
535 			tp->t_state &= ~TS_WCOLL;
536 		}
537 	}
538 	/*
539 	 * Now restart transmission unless the output queue is
540 	 * empty.
541 	 */
542 	if (tp->t_outq.c_cc == 0)
543 		goto out;
544 	if (1 || !(tp->t_oflag&OPOST))	/*XXX*/
545 		nch = ndqb(&tp->t_outq, 0);
546 	else {
547 		nch = ndqb(&tp->t_outq, 0200);
548 		/*
549 		 * If first thing on queue is a delay process it.
550 		 */
551 		if (nch == 0) {
552 			nch = getc(&tp->t_outq);
553 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
554 			tp->t_state |= TS_TIMEOUT;
555 			goto out;
556 		}
557 	}
558 	/*
559 	 * If characters to transmit, restart transmission.
560 	 */
561 	if (nch) {
562 		car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum);
563 		addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE;
564 		/*
565 		 * The following nonsense with short word
566 		 * is to make sure the dhbar |= word below
567 		 * is done with an interlocking bisw2 instruction.
568 		 */
569 		{ short word = 1 << unit;
570 		dhsar[dh] |= word;
571 		addr->dhcar = car;
572 		addr->dhbcr = -nch;
573 		addr->dhbar |= word;
574 		}
575 		tp->t_state |= TS_BUSY;
576 	}
577 out:
578 	splx(s);
579 }
580 
581 /*
582  * Stop output on a line, e.g. for ^S/^Q or output flush.
583  */
584 /*ARGSUSED*/
585 dhstop(tp, flag)
586 	register struct tty *tp;
587 {
588 	register struct dhdevice *addr;
589 	register int unit, s;
590 
591 	addr = (struct dhdevice *)tp->t_addr;
592 	/*
593 	 * Block input/output interrupts while messing with state.
594 	 */
595 	s = spl5();
596 	if (tp->t_state & TS_BUSY) {
597 		/*
598 		 * Device is transmitting; stop output
599 		 * by selecting the line and setting the byte
600 		 * count to -1.  We will clean up later
601 		 * by examining the address where the dh stopped.
602 		 */
603 		unit = minor(tp->t_dev);
604 		addr->un.dhcsrl = (unit&017) | DH_IE;
605 		if ((tp->t_state&TS_TTSTOP)==0)
606 			tp->t_state |= TS_FLUSH;
607 		addr->dhbcr = -1;
608 	}
609 	splx(s);
610 }
611 
612 /*
613  * Reset state of driver if UBA reset was necessary.
614  * Reset the csrl and lpr registers on open lines, and
615  * restart transmitters.
616  */
617 dhreset(uban)
618 	int uban;
619 {
620 	register int dh, unit;
621 	register struct tty *tp;
622 	register struct uba_device *ui;
623 	int i;
624 
625 	dh = 0;
626 	for (dh = 0; dh < NDH; dh++) {
627 		ui = dhinfo[dh];
628 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
629 			continue;
630 		printf(" dh%d", dh);
631 		if (dh_uballoc[uban] == dh) {
632 			int info;
633 
634 			info = uballoc(uban, (caddr_t)cfree,
635 			    nclist * sizeof(struct cblock), UBA_CANTWAIT);
636 			if (info)
637 				cbase[uban] = UBAI_ADDR(info);
638 			else {
639 				printf(" [can't get uba map]");
640 				cbase[uban] = -1;
641 			}
642 		}
643 		((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE;
644 		((struct dhdevice *)ui->ui_addr)->dhsilo = 0;
645 		unit = dh * 16;
646 		for (i = 0; i < 16; i++) {
647 			tp = &dh11[unit];
648 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
649 				dhparam(unit);
650 				dmctl(unit, DML_ON, DMSET);
651 				tp->t_state &= ~TS_BUSY;
652 				dhstart(tp);
653 			}
654 			unit++;
655 		}
656 	}
657 	dhsilos = 0;
658 }
659 
660 int dhtransitions, dhslowtimers, dhfasttimers;		/*DEBUG*/
661 /*
662  * At software clock interrupt time, check status.
663  * Empty all the dh silos that are in use, and decide whether
664  * to turn any silos off or on.
665  */
666 dhtimer()
667 {
668 	register int dh, s;
669 	static int timercalls;
670 
671 	if (dhsilos) {
672 		dhfasttimers++;		/*DEBUG*/
673 		timercalls++;
674 		s = spl5();
675 		for (dh = 0; dh < NDH; dh++)
676 			if (dhsilos & (1 << dh))
677 				dhrint(dh);
678 		splx(s);
679 	}
680 	if ((dhsilos == 0) || ((timercalls += FASTTIMER) >= hz)) {
681 		dhslowtimers++;		/*DEBUG*/
682 		timercalls = 0;
683 		for (dh = 0; dh < NDH; dh++) {
684 		    ave(dhrate[dh], dhchars[dh], 8);
685 		    if ((dhchars[dh] > dhhighrate) &&
686 		      ((dhsilos & (1 << dh)) == 0)) {
687 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo =
688 			    (dhchars[dh] > 500? 32 : 16);
689 			dhsilos |= (1 << dh);
690 			dhtransitions++;		/*DEBUG*/
691 		    } else if ((dhsilos & (1 << dh)) &&
692 		      (dhrate[dh] < dhlowrate)) {
693 			((struct dhdevice *)(dhinfo[dh]->ui_addr))->dhsilo = 0;
694 			dhsilos &= ~(1 << dh);
695 		    }
696 		    dhchars[dh] = 0;
697 		}
698 	}
699 	timeout(dhtimer, (caddr_t) 0, dhsilos? FASTTIMER: hz);
700 }
701 
702 /*
703  * Turn on the line associated with dh dev.
704  */
705 dmopen(dev, flag)
706 	dev_t dev;
707 {
708 	register struct tty *tp;
709 	register struct dmdevice *addr;
710 	register struct uba_device *ui;
711 	register int unit;
712 	register int dm;
713 	int s, error = 0;
714 
715 	unit = minor(dev);
716 	dm = unit >> 4;
717 	tp = &dh11[unit];
718 	unit &= 0xf;
719 	if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
720 		tp->t_state |= TS_CARR_ON;
721 		return (0);
722 	}
723 	addr = (struct dmdevice *)ui->ui_addr;
724 	s = spl5();
725 	for (;;) {
726 		tp->t_state |= TS_WOPEN;
727 		addr->dmcsr &= ~DM_SE;
728 		while (addr->dmcsr & DM_BUSY)
729 			;
730 		addr->dmcsr = unit;
731 		addr->dmlstat = DML_ON;
732 		if ((addr->dmlstat & DML_CAR) || (dhsoftCAR[dm] & (1 << unit)))
733 			tp->t_state |= TS_CARR_ON;
734 		addr->dmcsr = DM_IE|DM_SE;
735 		if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK ||
736 		    tp->t_cflag&CLOCAL)
737 			break;
738 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
739 		    ttopen, 0))
740 			break;
741 	}
742 	splx(s);
743 	return (error);
744 }
745 
746 /*
747  * Dump control bits into the DM registers.
748  */
749 dmctl(dev, bits, how)
750 	dev_t dev;
751 	int bits, how;
752 {
753 	register struct uba_device *ui;
754 	register struct dmdevice *addr;
755 	register int unit, s;
756 	int dm;
757 
758 	unit = minor(dev);
759 	dm = unit >> 4;
760 	if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
761 		return;
762 	addr = (struct dmdevice *)ui->ui_addr;
763 	s = spl5();
764 	addr->dmcsr &= ~DM_SE;
765 	while (addr->dmcsr & DM_BUSY)
766 		;
767 	addr->dmcsr = unit & 0xf;
768 	switch(how) {
769 	case DMSET:
770 		addr->dmlstat = bits;
771 		break;
772 	case DMBIS:
773 		addr->dmlstat |= bits;
774 		break;
775 	case DMBIC:
776 		addr->dmlstat &= ~bits;
777 		break;
778 	}
779 	addr->dmcsr = DM_IE|DM_SE;
780 	splx(s);
781 }
782 
783 /*
784  * DM11 interrupt; deal with carrier transitions.
785  */
786 dmintr(dm)
787 	register int dm;
788 {
789 	register struct uba_device *ui;
790 	register struct tty *tp;
791 	register struct dmdevice *addr;
792 	int unit;
793 
794 	ui = dminfo[dm];
795 	if (ui == 0)
796 		return;
797 	addr = (struct dmdevice *)ui->ui_addr;
798 	if (addr->dmcsr&DM_DONE) {
799 		if (addr->dmcsr&DM_CF) {
800 			unit = addr->dmcsr & 0xf;
801 			tp = &dh11[(dm << 4) + unit];
802 			if (addr->dmlstat & DML_CAR)
803 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
804 			else if ((dhsoftCAR[dm] & (1<<unit)) == 0 &&
805 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
806 				addr->dmlstat = 0;
807 		}
808 		addr->dmcsr = DM_IE|DM_SE;
809 	}
810 }
811 #endif
812