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