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