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 */
dcprobe(cp)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
dcopen(dev,flag,mode,p)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*/
dcclose(dev,flag,mode,p)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
dcread(dev,uio,flag)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
dcwrite(dev,uio,flag)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*/
dcioctl(dev,cmd,data,flag,p)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
dcparam(tp,t)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
dcintr(unit)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
dcrint(unit)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 = ¤tRep;
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
dcxint(tp)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
dcstart(tp)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*/
dcstop(tp,flag)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
dcmctl(dev,bits,how)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
dcscan(arg)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
dcGetc(dev)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
dcPutc(dev,c)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