xref: /original-bsd/sys/pmax/dev/dc.c (revision 4a884f8b)
1 /*-
2  * Copyright (c) 1992 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Ralph Campbell and Rick Macklem.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)dc.c	7.12 (Berkeley) 12/20/92
11  */
12 
13 /*
14  * devDC7085.c --
15  *
16  *     	This file contains machine-dependent routines that handle the
17  *	output queue for the serial lines.
18  *
19  *	Copyright (C) 1989 Digital Equipment Corporation.
20  *	Permission to use, copy, modify, and distribute this software and
21  *	its documentation for any purpose and without fee is hereby granted,
22  *	provided that the above copyright notice appears in all copies.
23  *	Digital Equipment Corporation makes no representations about the
24  *	suitability of this software for any purpose.  It is provided "as is"
25  *	without express or implied warranty.
26  *
27  * from: $Header: /sprite/src/kernel/dev/ds3100.md/RCS/devDC7085.c,
28  *	v 1.4 89/08/29 11:55:30 nelson Exp $ SPRITE (DECWRL)";
29  */
30 
31 #include <dc.h>
32 #if NDC > 0
33 /*
34  * DC7085 (DZ-11 look alike) Driver
35  */
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/ioctl.h>
39 #include <sys/tty.h>
40 #include <sys/proc.h>
41 #include <sys/map.h>
42 #include <sys/buf.h>
43 #include <sys/conf.h>
44 #include <sys/file.h>
45 #include <sys/uio.h>
46 #include <sys/kernel.h>
47 #include <sys/syslog.h>
48 
49 #include <machine/dc7085cons.h>
50 #include <machine/pmioctl.h>
51 
52 #include <pmax/pmax/pmaxtype.h>
53 #include <pmax/pmax/cons.h>
54 
55 #include <pmax/dev/device.h>
56 #include <pmax/dev/pdma.h>
57 #include <pmax/dev/fbreg.h>
58 
59 extern int pmax_boardtype;
60 extern struct consdev cn_tab;
61 
62 /*
63  * Driver information for auto-configuration stuff.
64  */
65 int	dcprobe();
66 void	dcintr();
67 struct	driver dcdriver = {
68 	"dc", dcprobe, 0, 0, dcintr,
69 };
70 
71 #define	NDCLINE 	(NDC*4)
72 
73 void dcstart	__P((struct tty *));
74 void dcxint	__P((struct tty *));
75 void dcPutc	__P((dev_t, int));
76 void dcscan	__P((void *));
77 extern void ttrstrt __P((void *));
78 int dcGetc	__P((dev_t));
79 int dcparam	__P((struct tty *, struct termios *));
80 extern void KBDReset	__P((dev_t, void (*)()));
81 extern void MouseInit	__P((dev_t, void (*)(), int (*)()));
82 
83 struct	tty dc_tty[NDCLINE];
84 int	dc_cnt = NDCLINE;
85 void	(*dcDivertXInput)();	/* X windows keyboard input routine */
86 void	(*dcMouseEvent)();	/* X windows mouse motion event routine */
87 void	(*dcMouseButtons)();	/* X windows mouse buttons event routine */
88 #ifdef DEBUG
89 int	debugChar;
90 #endif
91 
92 /*
93  * Software copy of brk register since it isn't readable
94  */
95 int	dc_brk[NDC];
96 char	dcsoftCAR[NDC];		/* mask of dc's with carrier on (DSR) */
97 
98 /*
99  * The DC7085 doesn't interrupt on carrier transitions, so
100  * we have to use a timer to watch it.
101  */
102 int	dc_timer;		/* true if timer started */
103 
104 /*
105  * Pdma structures for fast output code
106  */
107 struct	pdma dcpdma[NDCLINE];
108 
109 struct speedtab dcspeedtab[] = {
110 	0,	0,
111 	50,	LPR_B50,
112 	75,	LPR_B75,
113 	110,	LPR_B110,
114 	134,	LPR_B134,
115 	150,	LPR_B150,
116 	300,	LPR_B300,
117 	600,	LPR_B600,
118 	1200,	LPR_B1200,
119 	1800,	LPR_B1800,
120 	2400,	LPR_B2400,
121 	4800,	LPR_B4800,
122 	9600,	LPR_B9600,
123 	19200,	LPR_B19200,
124 	-1,	-1
125 };
126 
127 #ifndef	PORTSELECTOR
128 #define	ISPEED	TTYDEF_SPEED
129 #define	LFLAG	TTYDEF_LFLAG
130 #else
131 #define	ISPEED	B4800
132 #define	LFLAG	(TTYDEF_LFLAG & ~ECHO)
133 #endif
134 
135 /*
136  * Test to see if device is present.
137  * Return true if found and initialized ok.
138  */
139 dcprobe(cp)
140 	register struct pmax_ctlr *cp;
141 {
142 	register dcregs *dcaddr;
143 	register struct pdma *pdp;
144 	register struct tty *tp;
145 	register int cntr;
146 	int s;
147 
148 	if (cp->pmax_unit >= NDC)
149 		return (0);
150 	if (badaddr(cp->pmax_addr, 2))
151 		return (0);
152 
153 	/*
154 	 * For a remote console, wait a while for previous output to
155 	 * complete.
156 	 */
157 	if (major(cn_tab.cn_dev) == DCDEV && cp->pmax_unit == 0 &&
158 		cn_tab.cn_screen == 0)
159 		DELAY(10000);
160 
161 	/* reset chip */
162 	dcaddr = (dcregs *)cp->pmax_addr;
163 	dcaddr->dc_csr = CSR_CLR;
164 	MachEmptyWriteBuffer();
165 	while (dcaddr->dc_csr & CSR_CLR)
166 		;
167 	dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE;
168 
169 	/* init pseudo DMA structures */
170 	pdp = &dcpdma[cp->pmax_unit * 4];
171 	tp = &dc_tty[cp->pmax_unit * 4];
172 	for (cntr = 0; cntr < 4; cntr++) {
173 		pdp->p_addr = (void *)dcaddr;
174 		pdp->p_arg = (int)tp;
175 		pdp->p_fcn = dcxint;
176 		tp->t_addr = (caddr_t)pdp;
177 		pdp++, tp++;
178 	}
179 	dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB;
180 
181 	if (dc_timer == 0) {
182 		dc_timer = 1;
183 		timeout(dcscan, (void *)0, hz);
184 	}
185 
186 	/*
187 	 * Special handling for consoles.
188 	 */
189 	if (cp->pmax_unit == 0) {
190 		if (cn_tab.cn_screen) {
191 			s = spltty();
192 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
193 				LPR_B4800 | DCKBD_PORT;
194 			dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
195 				LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
196 			MachEmptyWriteBuffer();
197 			DELAY(1000);
198 			KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc);
199 			MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc);
200 			splx(s);
201 		} else if (major(cn_tab.cn_dev) == DCDEV) {
202 			s = spltty();
203 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
204 				LPR_B9600 | minor(cn_tab.cn_dev);
205 			MachEmptyWriteBuffer();
206 			DELAY(1000);
207 			cn_tab.cn_disabled = 0;
208 			splx(s);
209 		}
210 	}
211 	printf("dc%d at nexus0 csr 0x%x priority %d\n",
212 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
213 	return (1);
214 }
215 
216 dcopen(dev, flag, mode, p)
217 	dev_t dev;
218 	int flag, mode;
219 	struct proc *p;
220 {
221 	register struct tty *tp;
222 	register int unit;
223 	int s, error = 0;
224 
225 	unit = minor(dev);
226 	if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0)
227 		return (ENXIO);
228 	tp = &dc_tty[unit];
229 	tp->t_addr = (caddr_t)&dcpdma[unit];
230 	tp->t_oproc = dcstart;
231 	tp->t_param = dcparam;
232 	tp->t_dev = dev;
233 	if ((tp->t_state & TS_ISOPEN) == 0) {
234 		tp->t_state |= TS_WOPEN;
235 		ttychars(tp);
236 #ifndef PORTSELECTOR
237 		if (tp->t_ispeed == 0) {
238 #endif
239 			tp->t_iflag = TTYDEF_IFLAG;
240 			tp->t_oflag = TTYDEF_OFLAG;
241 			tp->t_cflag = TTYDEF_CFLAG;
242 			tp->t_lflag = LFLAG;
243 			tp->t_ispeed = tp->t_ospeed = ISPEED;
244 #ifdef PORTSELECTOR
245 			tp->t_cflag |= HUPCL;
246 #else
247 		}
248 #endif
249 		(void) dcparam(tp, &tp->t_termios);
250 		ttsetwater(tp);
251 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
252 		return (EBUSY);
253 	(void) dcmctl(dev, DML_DTR, DMSET);
254 	s = spltty();
255 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
256 	       !(tp->t_state & TS_CARR_ON)) {
257 		tp->t_state |= TS_WOPEN;
258 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
259 		    ttopen, 0))
260 			break;
261 	}
262 	splx(s);
263 	if (error)
264 		return (error);
265 	return ((*linesw[tp->t_line].l_open)(dev, tp));
266 }
267 
268 /*ARGSUSED*/
269 dcclose(dev, flag, mode, p)
270 	dev_t dev;
271 	int flag, mode;
272 	struct proc *p;
273 {
274 	register struct tty *tp;
275 	register int unit, bit;
276 
277 	unit = minor(dev);
278 	tp = &dc_tty[unit];
279 	bit = 1 << ((unit & 03) + 8);
280 	if (dc_brk[unit >> 2] & bit) {
281 		dc_brk[unit >> 2] &= ~bit;
282 		ttyoutput(0, tp);
283 	}
284 	(*linesw[tp->t_line].l_close)(tp, flag);
285 	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
286 	    !(tp->t_state & TS_ISOPEN))
287 		(void) dcmctl(dev, 0, DMSET);
288 	return (ttyclose(tp));
289 }
290 
291 dcread(dev, uio, flag)
292 	dev_t dev;
293 	struct uio *uio;
294 {
295 	register struct tty *tp;
296 
297 	tp = &dc_tty[minor(dev)];
298 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
299 }
300 
301 dcwrite(dev, uio, flag)
302 	dev_t dev;
303 	struct uio *uio;
304 {
305 	register struct tty *tp;
306 
307 	tp = &dc_tty[minor(dev)];
308 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
309 }
310 
311 /*ARGSUSED*/
312 dcioctl(dev, cmd, data, flag, p)
313 	dev_t dev;
314 	int cmd;
315 	caddr_t data;
316 	int flag;
317 	struct proc *p;
318 {
319 	register struct tty *tp;
320 	register int unit = minor(dev);
321 	register int dc = unit >> 2;
322 	int error;
323 
324 	tp = &dc_tty[unit];
325 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
326 	if (error >= 0)
327 		return (error);
328 	error = ttioctl(tp, cmd, data, flag);
329 	if (error >= 0)
330 		return (error);
331 
332 	switch (cmd) {
333 
334 	case TIOCSBRK:
335 		dc_brk[dc] |= 1 << ((unit & 03) + 8);
336 		ttyoutput(0, tp);
337 		break;
338 
339 	case TIOCCBRK:
340 		dc_brk[dc] &= ~(1 << ((unit & 03) + 8));
341 		ttyoutput(0, tp);
342 		break;
343 
344 	case TIOCSDTR:
345 		(void) dcmctl(dev, DML_DTR|DML_RTS, DMBIS);
346 		break;
347 
348 	case TIOCCDTR:
349 		(void) dcmctl(dev, DML_DTR|DML_RTS, DMBIC);
350 		break;
351 
352 	case TIOCMSET:
353 		(void) dcmctl(dev, *(int *)data, DMSET);
354 		break;
355 
356 	case TIOCMBIS:
357 		(void) dcmctl(dev, *(int *)data, DMBIS);
358 		break;
359 
360 	case TIOCMBIC:
361 		(void) dcmctl(dev, *(int *)data, DMBIC);
362 		break;
363 
364 	case TIOCMGET:
365 		*(int *)data = dcmctl(dev, 0, DMGET);
366 		break;
367 
368 	default:
369 		return (ENOTTY);
370 	}
371 	return (0);
372 }
373 
374 dcparam(tp, t)
375 	register struct tty *tp;
376 	register struct termios *t;
377 {
378 	register dcregs *dcaddr;
379 	register int lpr;
380 	register int cflag = t->c_cflag;
381 	int unit = minor(tp->t_dev);
382 	int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab);
383 
384 	/* check requested parameters */
385         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
386             (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 ||
387 	    (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200))
388                 return (EINVAL);
389         /* and copy to tty */
390         tp->t_ispeed = t->c_ispeed;
391         tp->t_ospeed = t->c_ospeed;
392         tp->t_cflag = cflag;
393 
394 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
395 
396 	/*
397 	 * Handle console cases specially.
398 	 */
399 	if (cn_tab.cn_screen) {
400 		if (unit == DCKBD_PORT) {
401 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
402 				LPR_B4800 | DCKBD_PORT;
403 			MachEmptyWriteBuffer();
404 			return (0);
405 		} else if (unit == DCMOUSE_PORT) {
406 			dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
407 				LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
408 			MachEmptyWriteBuffer();
409 			return (0);
410 		}
411 	} else if (tp->t_dev == cn_tab.cn_dev) {
412 		dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
413 			LPR_B9600 | unit;
414 		MachEmptyWriteBuffer();
415 		return (0);
416 	}
417 	if (ospeed == 0) {
418 		(void) dcmctl(unit, 0, DMSET);	/* hang up line */
419 		return (0);
420 	}
421 	lpr = LPR_RXENAB | ospeed | (unit & 03);
422 	if ((cflag & CSIZE) == CS7)
423 		lpr |= LPR_7_BIT_CHAR;
424 	else
425 		lpr |= LPR_8_BIT_CHAR;
426 	if (cflag & PARENB)
427 		lpr |= LPR_PARENB;
428 	if (cflag & PARODD)
429 		lpr |= LPR_OPAR;
430 	if (cflag & CSTOPB)
431 		lpr |= LPR_2_STOP;
432 	dcaddr->dc_lpr = lpr;
433 	MachEmptyWriteBuffer();
434 	return (0);
435 }
436 
437 /*
438  * Check for interrupts from all devices.
439  */
440 void
441 dcintr(unit)
442 	register int unit;
443 {
444 	register dcregs *dcaddr;
445 	register unsigned csr;
446 
447 	unit <<= 2;
448 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
449 	while ((csr = dcaddr->dc_csr) & (CSR_RDONE | CSR_TRDY)) {
450 		if (csr & CSR_RDONE)
451 			dcrint(unit);
452 		if (csr & CSR_TRDY)
453 			dcxint(&dc_tty[unit + ((csr >> 8) & 03)]);
454 	}
455 }
456 
457 dcrint(unit)
458 	register int unit;
459 {
460 	register dcregs *dcaddr;
461 	register struct tty *tp;
462 	register int c, cc;
463 	register struct tty *tp0;
464 	int overrun = 0;
465 
466 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
467 	tp0 = &dc_tty[unit];
468 	while ((c = dcaddr->dc_rbuf) < 0) {	/* char present */
469 		cc = c & 0xff;
470 		tp = tp0 + ((c >> 8) & 03);
471 		if ((c & RBUF_OERR) && overrun == 0) {
472 			log(LOG_WARNING, "dc%d,%d: silo overflow\n", unit >> 2,
473 				(c >> 8) & 03);
474 			overrun = 1;
475 		}
476 		/* the keyboard requires special translation */
477 		if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
478 #ifdef KADB
479 			if (cc == LK_DO) {
480 				spl0();
481 				kdbpanic();
482 				return;
483 			}
484 #endif
485 #ifdef DEBUG
486 			debugChar = cc;
487 #endif
488 			if (dcDivertXInput) {
489 				(*dcDivertXInput)(cc);
490 				return;
491 			}
492 			if ((cc = kbdMapChar(cc)) < 0)
493 				return;
494 		} else if (tp == &dc_tty[DCMOUSE_PORT] && dcMouseButtons) {
495 			register MouseReport *mrp;
496 			static MouseReport currentRep;
497 
498 			mrp = &currentRep;
499 			mrp->byteCount++;
500 			if (cc & MOUSE_START_FRAME) {
501 				/*
502 				 * The first mouse report byte (button state).
503 				 */
504 				mrp->state = cc;
505 				if (mrp->byteCount > 1)
506 					mrp->byteCount = 1;
507 			} else if (mrp->byteCount == 2) {
508 				/*
509 				 * The second mouse report byte (delta x).
510 				 */
511 				mrp->dx = cc;
512 			} else if (mrp->byteCount == 3) {
513 				/*
514 				 * The final mouse report byte (delta y).
515 				 */
516 				mrp->dy = cc;
517 				mrp->byteCount = 0;
518 				if (mrp->dx != 0 || mrp->dy != 0) {
519 					/*
520 					 * If the mouse moved,
521 					 * post a motion event.
522 					 */
523 					(*dcMouseEvent)(mrp);
524 				}
525 				(*dcMouseButtons)(mrp);
526 			}
527 			return;
528 		}
529 		if (!(tp->t_state & TS_ISOPEN)) {
530 			wakeup((caddr_t)&tp->t_rawq);
531 #ifdef PORTSELECTOR
532 			if (!(tp->t_state & TS_WOPEN))
533 #endif
534 				return;
535 		}
536 		if (c & RBUF_FERR)
537 			cc |= TTY_FE;
538 		if (c & RBUF_PERR)
539 			cc |= TTY_PE;
540 		(*linesw[tp->t_line].l_rint)(cc, tp);
541 	}
542 	DELAY(10);
543 }
544 
545 void
546 dcxint(tp)
547 	register struct tty *tp;
548 {
549 	register struct pdma *dp;
550 	register dcregs *dcaddr;
551 
552 	dp = (struct pdma *)tp->t_addr;
553 	if (dp->p_mem < dp->p_end) {
554 		dcaddr = (dcregs *)dp->p_addr;
555 		dcaddr->dc_tdr = dc_brk[(tp - dc_tty) >> 2] | *dp->p_mem++;
556 		MachEmptyWriteBuffer();
557 		DELAY(10);
558 		return;
559 	}
560 	tp->t_state &= ~TS_BUSY;
561 	if (tp->t_state & TS_FLUSH)
562 		tp->t_state &= ~TS_FLUSH;
563 	else {
564 		ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
565 		dp->p_end = dp->p_mem = tp->t_outq.c_cf;
566 	}
567 	if (tp->t_line)
568 		(*linesw[tp->t_line].l_start)(tp);
569 	else
570 		dcstart(tp);
571 	if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
572 		((dcregs *)dp->p_addr)->dc_tcr &= ~(1 << (minor(tp->t_dev) & 03));
573 		MachEmptyWriteBuffer();
574 		DELAY(10);
575 	}
576 }
577 
578 void
579 dcstart(tp)
580 	register struct tty *tp;
581 {
582 	register struct pdma *dp;
583 	register dcregs *dcaddr;
584 	register int cc;
585 	int s;
586 
587 	dp = (struct pdma *)tp->t_addr;
588 	dcaddr = (dcregs *)dp->p_addr;
589 	s = spltty();
590 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
591 		goto out;
592 	if (tp->t_outq.c_cc <= tp->t_lowat) {
593 		if (tp->t_state & TS_ASLEEP) {
594 			tp->t_state &= ~TS_ASLEEP;
595 			wakeup((caddr_t)&tp->t_outq);
596 		}
597 		selwakeup(&tp->t_wsel);
598 	}
599 	if (tp->t_outq.c_cc == 0)
600 		goto out;
601 	/* handle console specially */
602 	if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
603 		while (tp->t_outq.c_cc > 0) {
604 			cc = getc(&tp->t_outq) & 0x7f;
605 			cnputc(cc);
606 		}
607 		/*
608 		 * After we flush the output queue we may need to wake
609 		 * up the process that made the output.
610 		 */
611 		if (tp->t_outq.c_cc <= tp->t_lowat) {
612 			if (tp->t_state & TS_ASLEEP) {
613 				tp->t_state &= ~TS_ASLEEP;
614 				wakeup((caddr_t)&tp->t_outq);
615 			}
616 			selwakeup(&tp->t_wsel);
617 		}
618 		goto out;
619 	}
620 	if (tp->t_flags & (RAW|LITOUT))
621 		cc = ndqb(&tp->t_outq, 0);
622 	else {
623 		cc = ndqb(&tp->t_outq, 0200);
624 		if (cc == 0) {
625 			cc = getc(&tp->t_outq);
626 			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
627 			tp->t_state |= TS_TIMEOUT;
628 			goto out;
629 		}
630 	}
631 	tp->t_state |= TS_BUSY;
632 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
633 	dp->p_end += cc;
634 	dcaddr->dc_tcr |= 1 << (minor(tp->t_dev) & 03);
635 	MachEmptyWriteBuffer();
636 out:
637 	splx(s);
638 }
639 
640 /*
641  * Stop output on a line.
642  */
643 /*ARGSUSED*/
644 dcstop(tp, flag)
645 	register struct tty *tp;
646 {
647 	register struct pdma *dp;
648 	register int s;
649 
650 	dp = (struct pdma *)tp->t_addr;
651 	s = spltty();
652 	if (tp->t_state & TS_BUSY) {
653 		dp->p_end = dp->p_mem;
654 		if (!(tp->t_state & TS_TTSTOP))
655 			tp->t_state |= TS_FLUSH;
656 	}
657 	splx(s);
658 }
659 
660 dcmctl(dev, bits, how)
661 	dev_t dev;
662 	int bits, how;
663 {
664 	register dcregs *dcaddr;
665 	register int unit, mbits;
666 	int b, s;
667 	register int msr;
668 
669 	unit = minor(dev);
670 	b = 1 << (unit & 03);
671 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
672 	s = spltty();
673 	/* only channel 2 has modem control (what about line 3?) */
674 	mbits = DML_DTR | DML_DSR | DML_CAR;
675 	switch (unit & 03) {
676 	case 2:
677 		mbits = 0;
678 		if (dcaddr->dc_tcr & TCR_DTR2)
679 			mbits |= DML_DTR;
680 		msr = dcaddr->dc_msr;
681 		if (msr & MSR_CD2)
682 			mbits |= DML_CAR;
683 		if (msr & MSR_DSR2) {
684 			if (pmax_boardtype == DS_PMAX)
685 				mbits |= DML_CAR | DML_DSR;
686 			else
687 				mbits |= DML_DSR;
688 		}
689 		break;
690 
691 	case 3:
692 		if (pmax_boardtype != DS_PMAX) {
693 			mbits = 0;
694 			if (dcaddr->dc_tcr & TCR_DTR3)
695 				mbits |= DML_DTR;
696 			msr = dcaddr->dc_msr;
697 			if (msr & MSR_CD3)
698 				mbits |= DML_CAR;
699 			if (msr & MSR_DSR3)
700 				mbits |= DML_DSR;
701 		}
702 	}
703 	switch (how) {
704 	case DMSET:
705 		mbits = bits;
706 		break;
707 
708 	case DMBIS:
709 		mbits |= bits;
710 		break;
711 
712 	case DMBIC:
713 		mbits &= ~bits;
714 		break;
715 
716 	case DMGET:
717 		(void) splx(s);
718 		return (mbits);
719 	}
720 	switch (unit & 03) {
721 	case 2:
722 		if (mbits & DML_DTR)
723 			dcaddr->dc_tcr |= TCR_DTR2;
724 		else
725 			dcaddr->dc_tcr &= ~TCR_DTR2;
726 		break;
727 
728 	case 3:
729 		if (pmax_boardtype != DS_PMAX) {
730 			if (mbits & DML_DTR)
731 				dcaddr->dc_tcr |= TCR_DTR3;
732 			else
733 				dcaddr->dc_tcr &= ~TCR_DTR3;
734 		}
735 	}
736 	if ((mbits & DML_DTR) && (dcsoftCAR[unit >> 2] & b))
737 		dc_tty[unit].t_state |= TS_CARR_ON;
738 	(void) splx(s);
739 	return (mbits);
740 }
741 
742 /*
743  * This is called by timeout() periodically.
744  * Check to see if modem status bits have changed.
745  */
746 void
747 dcscan(arg)
748 	void *arg;
749 {
750 	register dcregs *dcaddr;
751 	register struct tty *tp;
752 	register int i, bit, car;
753 	int s;
754 
755 	s = spltty();
756 	/* only channel 2 has modem control (what about line 3?) */
757 	dcaddr = (dcregs *)dcpdma[i = 2].p_addr;
758 	tp = &dc_tty[i];
759 	bit = TCR_DTR2;
760 	if (dcsoftCAR[i >> 2] & bit)
761 		car = 1;
762 	else
763 		car = dcaddr->dc_msr & MSR_DSR2;
764 	if (car) {
765 		/* carrier present */
766 		if (!(tp->t_state & TS_CARR_ON))
767 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
768 	} else if ((tp->t_state & TS_CARR_ON) &&
769 	    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
770 		dcaddr->dc_tcr &= ~bit;
771 	splx(s);
772 	timeout(dcscan, (void *)0, hz);
773 }
774 
775 /*
776  * ----------------------------------------------------------------------------
777  *
778  * dcGetc --
779  *
780  *	Read a character from a serial line.
781  *
782  * Results:
783  *	A character read from the serial port.
784  *
785  * Side effects:
786  *	None.
787  *
788  * ----------------------------------------------------------------------------
789  */
790 int
791 dcGetc(dev)
792 	dev_t dev;
793 {
794 	register dcregs *dcaddr;
795 	register int c;
796 	int s;
797 
798 	dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
799 	if (!dcaddr)
800 		return (0);
801 	s = spltty();
802 	for (;;) {
803 		if (!(dcaddr->dc_csr & CSR_RDONE))
804 			continue;
805 		c = dcaddr->dc_rbuf;
806 		DELAY(10);
807 		if (((c >> 8) & 03) == (minor(dev) & 03))
808 			break;
809 	}
810 	splx(s);
811 	return (c & 0xff);
812 }
813 
814 /*
815  * Send a char on a port, non interrupt driven.
816  */
817 void
818 dcPutc(dev, c)
819 	dev_t dev;
820 	int c;
821 {
822 	register dcregs *dcaddr;
823 	register u_short tcr;
824 	register int timeout;
825 	int s, line;
826 
827 	s = spltty();
828 
829 	dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
830 	tcr = dcaddr->dc_tcr;
831 	dcaddr->dc_tcr = tcr | (1 << minor(dev));
832 	MachEmptyWriteBuffer();
833 	DELAY(10);
834 	while (1) {
835 		/*
836 		 * Wait for transmitter to be not busy.
837 		 */
838 		timeout = 1000000;
839 		while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
840 			timeout--;
841 		if (timeout == 0) {
842 			printf("dcPutc: timeout waiting for CSR_TRDY\n");
843 			break;
844 		}
845 		line = (dcaddr->dc_csr >> 8) & 3;
846 		/*
847 		 * Check to be sure its the right port.
848 		 */
849 		if (line != minor(dev)) {
850 			tcr |= 1 << line;
851 			dcaddr->dc_tcr &= ~(1 << line);
852 			MachEmptyWriteBuffer();
853 			DELAY(10);
854 			continue;
855 		}
856 		/*
857 		 * Start sending the character.
858 		 */
859 		dcaddr->dc_tdr = dc_brk[0] | (c & 0xff);
860 		MachEmptyWriteBuffer();
861 		DELAY(10);
862 		/*
863 		 * Wait for character to be sent.
864 		 */
865 		while (1) {
866 			/*
867 			 * cc -O bug: this code produces and infinite loop!
868 			 * while (!(dcaddr->dc_csr & CSR_TRDY))
869 			 *	;
870 			 */
871 			timeout = 1000000;
872 			while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
873 				timeout--;
874 			line = (dcaddr->dc_csr >> 8) & 3;
875 			if (line != minor(dev)) {
876 				tcr |= 1 << line;
877 				dcaddr->dc_tcr &= ~(1 << line);
878 				MachEmptyWriteBuffer();
879 				DELAY(10);
880 				continue;
881 			}
882 			dcaddr->dc_tcr &= ~(1 << minor(dev));
883 			MachEmptyWriteBuffer();
884 			DELAY(10);
885 			break;
886 		}
887 		break;
888 	}
889 	/*
890 	 * Enable interrupts for other lines which became ready.
891 	 */
892 	if (tcr & 0xF) {
893 		dcaddr->dc_tcr = tcr;
894 		MachEmptyWriteBuffer();
895 		DELAY(10);
896 	}
897 
898 	splx(s);
899 }
900 #endif /* NDC */
901