xref: /csrg-svn/sys/pmax/dev/dc.c (revision 56819)
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.11 (Berkeley) 11/15/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 	/* reset chip */
154 	dcaddr = (dcregs *)cp->pmax_addr;
155 	dcaddr->dc_csr = CSR_CLR;
156 	MachEmptyWriteBuffer();
157 	while (dcaddr->dc_csr & CSR_CLR)
158 		;
159 	dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE;
160 
161 	/* init pseudo DMA structures */
162 	pdp = &dcpdma[cp->pmax_unit * 4];
163 	tp = &dc_tty[cp->pmax_unit * 4];
164 	for (cntr = 0; cntr < 4; cntr++) {
165 		pdp->p_addr = (void *)dcaddr;
166 		pdp->p_arg = (int)tp;
167 		pdp->p_fcn = dcxint;
168 		tp->t_addr = (caddr_t)pdp;
169 		pdp++, tp++;
170 	}
171 	dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB;
172 
173 	if (dc_timer == 0) {
174 		dc_timer = 1;
175 		timeout(dcscan, (void *)0, hz);
176 	}
177 	printf("dc%d at nexus0 csr 0x%x priority %d\n",
178 		cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
179 
180 	/*
181 	 * Special handling for consoles.
182 	 */
183 	if (cp->pmax_unit == 0) {
184 		if (cn_tab.cn_screen) {
185 			s = spltty();
186 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
187 				LPR_B4800 | DCKBD_PORT;
188 			dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
189 				LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
190 			MachEmptyWriteBuffer();
191 			KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc);
192 			MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc);
193 			splx(s);
194 		} else if (major(cn_tab.cn_dev) == DCDEV) {
195 			s = spltty();
196 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
197 				LPR_B9600 | minor(cn_tab.cn_dev);
198 			MachEmptyWriteBuffer();
199 			cn_tab.cn_disabled = 0;
200 			splx(s);
201 		}
202 	}
203 	return (1);
204 }
205 
206 dcopen(dev, flag, mode, p)
207 	dev_t dev;
208 	int flag, mode;
209 	struct proc *p;
210 {
211 	register struct tty *tp;
212 	register int unit;
213 	int s, error = 0;
214 
215 	unit = minor(dev);
216 	if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0)
217 		return (ENXIO);
218 	tp = &dc_tty[unit];
219 	tp->t_addr = (caddr_t)&dcpdma[unit];
220 	tp->t_oproc = dcstart;
221 	tp->t_param = dcparam;
222 	tp->t_dev = dev;
223 	if ((tp->t_state & TS_ISOPEN) == 0) {
224 		tp->t_state |= TS_WOPEN;
225 		ttychars(tp);
226 #ifndef PORTSELECTOR
227 		if (tp->t_ispeed == 0) {
228 #endif
229 			tp->t_iflag = TTYDEF_IFLAG;
230 			tp->t_oflag = TTYDEF_OFLAG;
231 			tp->t_cflag = TTYDEF_CFLAG;
232 			tp->t_lflag = LFLAG;
233 			tp->t_ispeed = tp->t_ospeed = ISPEED;
234 #ifdef PORTSELECTOR
235 			tp->t_cflag |= HUPCL;
236 #else
237 		}
238 #endif
239 		(void) dcparam(tp, &tp->t_termios);
240 		ttsetwater(tp);
241 	} else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
242 		return (EBUSY);
243 	(void) dcmctl(dev, DML_DTR, DMSET);
244 	s = spltty();
245 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
246 	       !(tp->t_state & TS_CARR_ON)) {
247 		tp->t_state |= TS_WOPEN;
248 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
249 		    ttopen, 0))
250 			break;
251 	}
252 	splx(s);
253 	if (error)
254 		return (error);
255 	return ((*linesw[tp->t_line].l_open)(dev, tp));
256 }
257 
258 /*ARGSUSED*/
259 dcclose(dev, flag, mode, p)
260 	dev_t dev;
261 	int flag, mode;
262 	struct proc *p;
263 {
264 	register struct tty *tp;
265 	register int unit, bit;
266 
267 	unit = minor(dev);
268 	tp = &dc_tty[unit];
269 	bit = 1 << ((unit & 03) + 8);
270 	if (dc_brk[unit >> 2] & bit) {
271 		dc_brk[unit >> 2] &= ~bit;
272 		ttyoutput(0, tp);
273 	}
274 	(*linesw[tp->t_line].l_close)(tp, flag);
275 	if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
276 	    !(tp->t_state & TS_ISOPEN))
277 		(void) dcmctl(dev, 0, DMSET);
278 	return (ttyclose(tp));
279 }
280 
281 dcread(dev, uio, flag)
282 	dev_t dev;
283 	struct uio *uio;
284 {
285 	register struct tty *tp;
286 
287 	tp = &dc_tty[minor(dev)];
288 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
289 }
290 
291 dcwrite(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_write)(tp, uio, flag));
299 }
300 
301 /*ARGSUSED*/
302 dcioctl(dev, cmd, data, flag, p)
303 	dev_t dev;
304 	int cmd;
305 	caddr_t data;
306 	int flag;
307 	struct proc *p;
308 {
309 	register struct tty *tp;
310 	register int unit = minor(dev);
311 	register int dc = unit >> 2;
312 	int error;
313 
314 	tp = &dc_tty[unit];
315 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
316 	if (error >= 0)
317 		return (error);
318 	error = ttioctl(tp, cmd, data, flag);
319 	if (error >= 0)
320 		return (error);
321 
322 	switch (cmd) {
323 
324 	case TIOCSBRK:
325 		dc_brk[dc] |= 1 << ((unit & 03) + 8);
326 		ttyoutput(0, tp);
327 		break;
328 
329 	case TIOCCBRK:
330 		dc_brk[dc] &= ~(1 << ((unit & 03) + 8));
331 		ttyoutput(0, tp);
332 		break;
333 
334 	case TIOCSDTR:
335 		(void) dcmctl(dev, DML_DTR|DML_RTS, DMBIS);
336 		break;
337 
338 	case TIOCCDTR:
339 		(void) dcmctl(dev, DML_DTR|DML_RTS, DMBIC);
340 		break;
341 
342 	case TIOCMSET:
343 		(void) dcmctl(dev, *(int *)data, DMSET);
344 		break;
345 
346 	case TIOCMBIS:
347 		(void) dcmctl(dev, *(int *)data, DMBIS);
348 		break;
349 
350 	case TIOCMBIC:
351 		(void) dcmctl(dev, *(int *)data, DMBIC);
352 		break;
353 
354 	case TIOCMGET:
355 		*(int *)data = dcmctl(dev, 0, DMGET);
356 		break;
357 
358 	default:
359 		return (ENOTTY);
360 	}
361 	return (0);
362 }
363 
364 dcparam(tp, t)
365 	register struct tty *tp;
366 	register struct termios *t;
367 {
368 	register dcregs *dcaddr;
369 	register int lpr;
370 	register int cflag = t->c_cflag;
371 	int unit = minor(tp->t_dev);
372 	int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab);
373 
374 	/* check requested parameters */
375         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) ||
376             (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 ||
377 	    (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200))
378                 return (EINVAL);
379         /* and copy to tty */
380         tp->t_ispeed = t->c_ispeed;
381         tp->t_ospeed = t->c_ospeed;
382         tp->t_cflag = cflag;
383 
384 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
385 
386 	/*
387 	 * Handle console cases specially.
388 	 */
389 	if (cn_tab.cn_screen) {
390 		if (unit == DCKBD_PORT) {
391 			dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
392 				LPR_B4800 | DCKBD_PORT;
393 			MachEmptyWriteBuffer();
394 			return (0);
395 		} else if (unit == DCMOUSE_PORT) {
396 			dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR |
397 				LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT;
398 			MachEmptyWriteBuffer();
399 			return (0);
400 		}
401 	} else if (tp->t_dev == cn_tab.cn_dev) {
402 		dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR |
403 			LPR_B9600 | unit;
404 		MachEmptyWriteBuffer();
405 		return (0);
406 	}
407 	if (ospeed == 0) {
408 		(void) dcmctl(unit, 0, DMSET);	/* hang up line */
409 		return (0);
410 	}
411 	lpr = LPR_RXENAB | ospeed | (unit & 03);
412 	if ((cflag & CSIZE) == CS7)
413 		lpr |= LPR_7_BIT_CHAR;
414 	else
415 		lpr |= LPR_8_BIT_CHAR;
416 	if (cflag & PARENB)
417 		lpr |= LPR_PARENB;
418 	if (cflag & PARODD)
419 		lpr |= LPR_OPAR;
420 	if (cflag & CSTOPB)
421 		lpr |= LPR_2_STOP;
422 	dcaddr->dc_lpr = lpr;
423 	MachEmptyWriteBuffer();
424 	return (0);
425 }
426 
427 /*
428  * Check for interrupts from all devices.
429  */
430 void
431 dcintr(unit)
432 	register int unit;
433 {
434 	register dcregs *dcaddr;
435 	register unsigned csr;
436 
437 	unit <<= 2;
438 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
439 	while ((csr = dcaddr->dc_csr) & (CSR_RDONE | CSR_TRDY)) {
440 		if (csr & CSR_RDONE)
441 			dcrint(unit);
442 		if (csr & CSR_TRDY)
443 			dcxint(&dc_tty[unit + ((csr >> 8) & 03)]);
444 	}
445 }
446 
447 dcrint(unit)
448 	register int unit;
449 {
450 	register dcregs *dcaddr;
451 	register struct tty *tp;
452 	register int c, cc;
453 	register struct tty *tp0;
454 	int overrun = 0;
455 
456 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
457 	tp0 = &dc_tty[unit];
458 	while ((c = dcaddr->dc_rbuf) < 0) {	/* char present */
459 		cc = c & 0xff;
460 		tp = tp0 + ((c >> 8) & 03);
461 		if ((c & RBUF_OERR) && overrun == 0) {
462 			log(LOG_WARNING, "dc%d,%d: silo overflow\n", unit >> 2,
463 				(c >> 8) & 03);
464 			overrun = 1;
465 		}
466 		/* the keyboard requires special translation */
467 		if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
468 #ifdef KADB
469 			if (cc == LK_DO) {
470 				spl0();
471 				kdbpanic();
472 				return;
473 			}
474 #endif
475 #ifdef DEBUG
476 			debugChar = cc;
477 #endif
478 			if (dcDivertXInput) {
479 				(*dcDivertXInput)(cc);
480 				return;
481 			}
482 			if ((cc = kbdMapChar(cc)) < 0)
483 				return;
484 		} else if (tp == &dc_tty[DCMOUSE_PORT] && dcMouseButtons) {
485 			register MouseReport *mrp;
486 			static MouseReport currentRep;
487 
488 			mrp = &currentRep;
489 			mrp->byteCount++;
490 			if (cc & MOUSE_START_FRAME) {
491 				/*
492 				 * The first mouse report byte (button state).
493 				 */
494 				mrp->state = cc;
495 				if (mrp->byteCount > 1)
496 					mrp->byteCount = 1;
497 			} else if (mrp->byteCount == 2) {
498 				/*
499 				 * The second mouse report byte (delta x).
500 				 */
501 				mrp->dx = cc;
502 			} else if (mrp->byteCount == 3) {
503 				/*
504 				 * The final mouse report byte (delta y).
505 				 */
506 				mrp->dy = cc;
507 				mrp->byteCount = 0;
508 				if (mrp->dx != 0 || mrp->dy != 0) {
509 					/*
510 					 * If the mouse moved,
511 					 * post a motion event.
512 					 */
513 					(*dcMouseEvent)(mrp);
514 				}
515 				(*dcMouseButtons)(mrp);
516 			}
517 			return;
518 		}
519 		if (!(tp->t_state & TS_ISOPEN)) {
520 			wakeup((caddr_t)&tp->t_rawq);
521 #ifdef PORTSELECTOR
522 			if (!(tp->t_state & TS_WOPEN))
523 #endif
524 				return;
525 		}
526 		if (c & RBUF_FERR)
527 			cc |= TTY_FE;
528 		if (c & RBUF_PERR)
529 			cc |= TTY_PE;
530 		(*linesw[tp->t_line].l_rint)(cc, tp);
531 	}
532 	DELAY(10);
533 }
534 
535 void
536 dcxint(tp)
537 	register struct tty *tp;
538 {
539 	register struct pdma *dp;
540 	register dcregs *dcaddr;
541 
542 	dp = (struct pdma *)tp->t_addr;
543 	if (dp->p_mem < dp->p_end) {
544 		dcaddr = (dcregs *)dp->p_addr;
545 		dcaddr->dc_tdr = dc_brk[(tp - dc_tty) >> 2] | *dp->p_mem++;
546 		MachEmptyWriteBuffer();
547 		DELAY(10);
548 		return;
549 	}
550 	tp->t_state &= ~TS_BUSY;
551 	if (tp->t_state & TS_FLUSH)
552 		tp->t_state &= ~TS_FLUSH;
553 	else {
554 		ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
555 		dp->p_end = dp->p_mem = tp->t_outq.c_cf;
556 	}
557 	if (tp->t_line)
558 		(*linesw[tp->t_line].l_start)(tp);
559 	else
560 		dcstart(tp);
561 	if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
562 		((dcregs *)dp->p_addr)->dc_tcr &= ~(1 << (minor(tp->t_dev) & 03));
563 		MachEmptyWriteBuffer();
564 		DELAY(10);
565 	}
566 }
567 
568 void
569 dcstart(tp)
570 	register struct tty *tp;
571 {
572 	register struct pdma *dp;
573 	register dcregs *dcaddr;
574 	register int cc;
575 	int s;
576 
577 	dp = (struct pdma *)tp->t_addr;
578 	dcaddr = (dcregs *)dp->p_addr;
579 	s = spltty();
580 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
581 		goto out;
582 	if (tp->t_outq.c_cc <= tp->t_lowat) {
583 		if (tp->t_state & TS_ASLEEP) {
584 			tp->t_state &= ~TS_ASLEEP;
585 			wakeup((caddr_t)&tp->t_outq);
586 		}
587 		selwakeup(&tp->t_wsel);
588 	}
589 	if (tp->t_outq.c_cc == 0)
590 		goto out;
591 	/* handle console specially */
592 	if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) {
593 		while (tp->t_outq.c_cc > 0) {
594 			cc = getc(&tp->t_outq) & 0x7f;
595 			cnputc(cc);
596 		}
597 		/*
598 		 * After we flush the output queue we may need to wake
599 		 * up the process that made the output.
600 		 */
601 		if (tp->t_outq.c_cc <= tp->t_lowat) {
602 			if (tp->t_state & TS_ASLEEP) {
603 				tp->t_state &= ~TS_ASLEEP;
604 				wakeup((caddr_t)&tp->t_outq);
605 			}
606 			selwakeup(&tp->t_wsel);
607 		}
608 		goto out;
609 	}
610 	if (tp->t_flags & (RAW|LITOUT))
611 		cc = ndqb(&tp->t_outq, 0);
612 	else {
613 		cc = ndqb(&tp->t_outq, 0200);
614 		if (cc == 0) {
615 			cc = getc(&tp->t_outq);
616 			timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
617 			tp->t_state |= TS_TIMEOUT;
618 			goto out;
619 		}
620 	}
621 	tp->t_state |= TS_BUSY;
622 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
623 	dp->p_end += cc;
624 	dcaddr->dc_tcr |= 1 << (minor(tp->t_dev) & 03);
625 	MachEmptyWriteBuffer();
626 out:
627 	splx(s);
628 }
629 
630 /*
631  * Stop output on a line.
632  */
633 /*ARGSUSED*/
634 dcstop(tp, flag)
635 	register struct tty *tp;
636 {
637 	register struct pdma *dp;
638 	register int s;
639 
640 	dp = (struct pdma *)tp->t_addr;
641 	s = spltty();
642 	if (tp->t_state & TS_BUSY) {
643 		dp->p_end = dp->p_mem;
644 		if (!(tp->t_state & TS_TTSTOP))
645 			tp->t_state |= TS_FLUSH;
646 	}
647 	splx(s);
648 }
649 
650 dcmctl(dev, bits, how)
651 	dev_t dev;
652 	int bits, how;
653 {
654 	register dcregs *dcaddr;
655 	register int unit, mbits;
656 	int b, s;
657 	register int msr;
658 
659 	unit = minor(dev);
660 	b = 1 << (unit & 03);
661 	dcaddr = (dcregs *)dcpdma[unit].p_addr;
662 	s = spltty();
663 	/* only channel 2 has modem control (what about line 3?) */
664 	mbits = DML_DTR | DML_DSR | DML_CAR;
665 	switch (unit & 03) {
666 	case 2:
667 		mbits = 0;
668 		if (dcaddr->dc_tcr & TCR_DTR2)
669 			mbits |= DML_DTR;
670 		msr = dcaddr->dc_msr;
671 		if (msr & MSR_CD2)
672 			mbits |= DML_CAR;
673 		if (msr & MSR_DSR2) {
674 			if (pmax_boardtype == DS_PMAX)
675 				mbits |= DML_CAR | DML_DSR;
676 			else
677 				mbits |= DML_DSR;
678 		}
679 		break;
680 
681 	case 3:
682 		if (pmax_boardtype != DS_PMAX) {
683 			mbits = 0;
684 			if (dcaddr->dc_tcr & TCR_DTR3)
685 				mbits |= DML_DTR;
686 			msr = dcaddr->dc_msr;
687 			if (msr & MSR_CD3)
688 				mbits |= DML_CAR;
689 			if (msr & MSR_DSR3)
690 				mbits |= DML_DSR;
691 		}
692 	}
693 	switch (how) {
694 	case DMSET:
695 		mbits = bits;
696 		break;
697 
698 	case DMBIS:
699 		mbits |= bits;
700 		break;
701 
702 	case DMBIC:
703 		mbits &= ~bits;
704 		break;
705 
706 	case DMGET:
707 		(void) splx(s);
708 		return (mbits);
709 	}
710 	switch (unit & 03) {
711 	case 2:
712 		if (mbits & DML_DTR)
713 			dcaddr->dc_tcr |= TCR_DTR2;
714 		else
715 			dcaddr->dc_tcr &= ~TCR_DTR2;
716 		break;
717 
718 	case 3:
719 		if (pmax_boardtype != DS_PMAX) {
720 			if (mbits & DML_DTR)
721 				dcaddr->dc_tcr |= TCR_DTR3;
722 			else
723 				dcaddr->dc_tcr &= ~TCR_DTR3;
724 		}
725 	}
726 	if ((mbits & DML_DTR) && (dcsoftCAR[unit >> 2] & b))
727 		dc_tty[unit].t_state |= TS_CARR_ON;
728 	(void) splx(s);
729 	return (mbits);
730 }
731 
732 /*
733  * This is called by timeout() periodically.
734  * Check to see if modem status bits have changed.
735  */
736 void
737 dcscan(arg)
738 	void *arg;
739 {
740 	register dcregs *dcaddr;
741 	register struct tty *tp;
742 	register int i, bit, car;
743 	int s;
744 
745 	s = spltty();
746 	/* only channel 2 has modem control (what about line 3?) */
747 	dcaddr = (dcregs *)dcpdma[i = 2].p_addr;
748 	tp = &dc_tty[i];
749 	bit = TCR_DTR2;
750 	if (dcsoftCAR[i >> 2] & bit)
751 		car = 1;
752 	else
753 		car = dcaddr->dc_msr & MSR_DSR2;
754 	if (car) {
755 		/* carrier present */
756 		if (!(tp->t_state & TS_CARR_ON))
757 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
758 	} else if ((tp->t_state & TS_CARR_ON) &&
759 	    (*linesw[tp->t_line].l_modem)(tp, 0) == 0)
760 		dcaddr->dc_tcr &= ~bit;
761 	splx(s);
762 	timeout(dcscan, (void *)0, hz);
763 }
764 
765 /*
766  * ----------------------------------------------------------------------------
767  *
768  * dcGetc --
769  *
770  *	Read a character from a serial line.
771  *
772  * Results:
773  *	A character read from the serial port.
774  *
775  * Side effects:
776  *	None.
777  *
778  * ----------------------------------------------------------------------------
779  */
780 int
781 dcGetc(dev)
782 	dev_t dev;
783 {
784 	register dcregs *dcaddr;
785 	register int c;
786 	int s;
787 
788 	dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
789 	if (!dcaddr)
790 		return (0);
791 	s = spltty();
792 	for (;;) {
793 		if (!(dcaddr->dc_csr & CSR_RDONE))
794 			continue;
795 		c = dcaddr->dc_rbuf;
796 		DELAY(10);
797 		if (((c >> 8) & 03) == (minor(dev) & 03))
798 			break;
799 	}
800 	splx(s);
801 	return (c & 0xff);
802 }
803 
804 /*
805  * Send a char on a port, non interrupt driven.
806  */
807 void
808 dcPutc(dev, c)
809 	dev_t dev;
810 	int c;
811 {
812 	register dcregs *dcaddr;
813 	register u_short tcr;
814 	register int timeout;
815 	int s, line;
816 
817 	s = spltty();
818 
819 	dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr;
820 	tcr = dcaddr->dc_tcr;
821 	dcaddr->dc_tcr = tcr | (1 << minor(dev));
822 	MachEmptyWriteBuffer();
823 	DELAY(10);
824 	while (1) {
825 		/*
826 		 * Wait for transmitter to be not busy.
827 		 */
828 		timeout = 1000000;
829 		while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
830 			timeout--;
831 		if (timeout == 0) {
832 			printf("dcPutc: timeout waiting for CSR_TRDY\n");
833 			break;
834 		}
835 		line = (dcaddr->dc_csr >> 8) & 3;
836 		/*
837 		 * Check to be sure its the right port.
838 		 */
839 		if (line != minor(dev)) {
840 			tcr |= 1 << line;
841 			dcaddr->dc_tcr &= ~(1 << line);
842 			MachEmptyWriteBuffer();
843 			DELAY(10);
844 			continue;
845 		}
846 		/*
847 		 * Start sending the character.
848 		 */
849 		dcaddr->dc_tdr = dc_brk[0] | (c & 0xff);
850 		MachEmptyWriteBuffer();
851 		DELAY(10);
852 		/*
853 		 * Wait for character to be sent.
854 		 */
855 		while (1) {
856 			/*
857 			 * cc -O bug: this code produces and infinite loop!
858 			 * while (!(dcaddr->dc_csr & CSR_TRDY))
859 			 *	;
860 			 */
861 			timeout = 1000000;
862 			while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0)
863 				timeout--;
864 			line = (dcaddr->dc_csr >> 8) & 3;
865 			if (line != minor(dev)) {
866 				tcr |= 1 << line;
867 				dcaddr->dc_tcr &= ~(1 << line);
868 				MachEmptyWriteBuffer();
869 				DELAY(10);
870 				continue;
871 			}
872 			dcaddr->dc_tcr &= ~(1 << minor(dev));
873 			MachEmptyWriteBuffer();
874 			DELAY(10);
875 			break;
876 		}
877 		break;
878 	}
879 	/*
880 	 * Enable interrupts for other lines which became ready.
881 	 */
882 	if (tcr & 0xF) {
883 		dcaddr->dc_tcr = tcr;
884 		MachEmptyWriteBuffer();
885 		DELAY(10);
886 	}
887 
888 	splx(s);
889 }
890 #endif /* NDC */
891