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