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