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 = ¤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 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