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