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.12 (Berkeley) 12/20/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 /* 154 * For a remote console, wait a while for previous output to 155 * complete. 156 */ 157 if (major(cn_tab.cn_dev) == DCDEV && cp->pmax_unit == 0 && 158 cn_tab.cn_screen == 0) 159 DELAY(10000); 160 161 /* reset chip */ 162 dcaddr = (dcregs *)cp->pmax_addr; 163 dcaddr->dc_csr = CSR_CLR; 164 MachEmptyWriteBuffer(); 165 while (dcaddr->dc_csr & CSR_CLR) 166 ; 167 dcaddr->dc_csr = CSR_MSE | CSR_TIE | CSR_RIE; 168 169 /* init pseudo DMA structures */ 170 pdp = &dcpdma[cp->pmax_unit * 4]; 171 tp = &dc_tty[cp->pmax_unit * 4]; 172 for (cntr = 0; cntr < 4; cntr++) { 173 pdp->p_addr = (void *)dcaddr; 174 pdp->p_arg = (int)tp; 175 pdp->p_fcn = dcxint; 176 tp->t_addr = (caddr_t)pdp; 177 pdp++, tp++; 178 } 179 dcsoftCAR[cp->pmax_unit] = cp->pmax_flags | 0xB; 180 181 if (dc_timer == 0) { 182 dc_timer = 1; 183 timeout(dcscan, (void *)0, hz); 184 } 185 186 /* 187 * Special handling for consoles. 188 */ 189 if (cp->pmax_unit == 0) { 190 if (cn_tab.cn_screen) { 191 s = spltty(); 192 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | 193 LPR_B4800 | DCKBD_PORT; 194 dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR | 195 LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT; 196 MachEmptyWriteBuffer(); 197 DELAY(1000); 198 KBDReset(makedev(DCDEV, DCKBD_PORT), dcPutc); 199 MouseInit(makedev(DCDEV, DCMOUSE_PORT), dcPutc, dcGetc); 200 splx(s); 201 } else if (major(cn_tab.cn_dev) == DCDEV) { 202 s = spltty(); 203 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | 204 LPR_B9600 | minor(cn_tab.cn_dev); 205 MachEmptyWriteBuffer(); 206 DELAY(1000); 207 cn_tab.cn_disabled = 0; 208 splx(s); 209 } 210 } 211 printf("dc%d at nexus0 csr 0x%x priority %d\n", 212 cp->pmax_unit, cp->pmax_addr, cp->pmax_pri); 213 return (1); 214 } 215 216 dcopen(dev, flag, mode, p) 217 dev_t dev; 218 int flag, mode; 219 struct proc *p; 220 { 221 register struct tty *tp; 222 register int unit; 223 int s, error = 0; 224 225 unit = minor(dev); 226 if (unit >= dc_cnt || dcpdma[unit].p_addr == (void *)0) 227 return (ENXIO); 228 tp = &dc_tty[unit]; 229 tp->t_addr = (caddr_t)&dcpdma[unit]; 230 tp->t_oproc = dcstart; 231 tp->t_param = dcparam; 232 tp->t_dev = dev; 233 if ((tp->t_state & TS_ISOPEN) == 0) { 234 tp->t_state |= TS_WOPEN; 235 ttychars(tp); 236 #ifndef PORTSELECTOR 237 if (tp->t_ispeed == 0) { 238 #endif 239 tp->t_iflag = TTYDEF_IFLAG; 240 tp->t_oflag = TTYDEF_OFLAG; 241 tp->t_cflag = TTYDEF_CFLAG; 242 tp->t_lflag = LFLAG; 243 tp->t_ispeed = tp->t_ospeed = ISPEED; 244 #ifdef PORTSELECTOR 245 tp->t_cflag |= HUPCL; 246 #else 247 } 248 #endif 249 (void) dcparam(tp, &tp->t_termios); 250 ttsetwater(tp); 251 } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0) 252 return (EBUSY); 253 (void) dcmctl(dev, DML_DTR, DMSET); 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 277 unit = minor(dev); 278 tp = &dc_tty[unit]; 279 bit = 1 << ((unit & 03) + 8); 280 if (dc_brk[unit >> 2] & bit) { 281 dc_brk[unit >> 2] &= ~bit; 282 ttyoutput(0, tp); 283 } 284 (*linesw[tp->t_line].l_close)(tp, flag); 285 if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) || 286 !(tp->t_state & TS_ISOPEN)) 287 (void) dcmctl(dev, 0, DMSET); 288 return (ttyclose(tp)); 289 } 290 291 dcread(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_read)(tp, uio, flag)); 299 } 300 301 dcwrite(dev, uio, flag) 302 dev_t dev; 303 struct uio *uio; 304 { 305 register struct tty *tp; 306 307 tp = &dc_tty[minor(dev)]; 308 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 309 } 310 311 /*ARGSUSED*/ 312 dcioctl(dev, cmd, data, flag, p) 313 dev_t dev; 314 int cmd; 315 caddr_t data; 316 int flag; 317 struct proc *p; 318 { 319 register struct tty *tp; 320 register int unit = minor(dev); 321 register int dc = unit >> 2; 322 int error; 323 324 tp = &dc_tty[unit]; 325 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 326 if (error >= 0) 327 return (error); 328 error = ttioctl(tp, cmd, data, flag); 329 if (error >= 0) 330 return (error); 331 332 switch (cmd) { 333 334 case TIOCSBRK: 335 dc_brk[dc] |= 1 << ((unit & 03) + 8); 336 ttyoutput(0, tp); 337 break; 338 339 case TIOCCBRK: 340 dc_brk[dc] &= ~(1 << ((unit & 03) + 8)); 341 ttyoutput(0, tp); 342 break; 343 344 case TIOCSDTR: 345 (void) dcmctl(dev, DML_DTR|DML_RTS, DMBIS); 346 break; 347 348 case TIOCCDTR: 349 (void) dcmctl(dev, DML_DTR|DML_RTS, DMBIC); 350 break; 351 352 case TIOCMSET: 353 (void) dcmctl(dev, *(int *)data, DMSET); 354 break; 355 356 case TIOCMBIS: 357 (void) dcmctl(dev, *(int *)data, DMBIS); 358 break; 359 360 case TIOCMBIC: 361 (void) dcmctl(dev, *(int *)data, DMBIC); 362 break; 363 364 case TIOCMGET: 365 *(int *)data = dcmctl(dev, 0, DMGET); 366 break; 367 368 default: 369 return (ENOTTY); 370 } 371 return (0); 372 } 373 374 dcparam(tp, t) 375 register struct tty *tp; 376 register struct termios *t; 377 { 378 register dcregs *dcaddr; 379 register int lpr; 380 register int cflag = t->c_cflag; 381 int unit = minor(tp->t_dev); 382 int ospeed = ttspeedtab(t->c_ospeed, dcspeedtab); 383 384 /* check requested parameters */ 385 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) || 386 (cflag & CSIZE) == CS5 || (cflag & CSIZE) == CS6 || 387 (pmax_boardtype == DS_PMAX && t->c_ospeed == 19200)) 388 return (EINVAL); 389 /* and copy to tty */ 390 tp->t_ispeed = t->c_ispeed; 391 tp->t_ospeed = t->c_ospeed; 392 tp->t_cflag = cflag; 393 394 dcaddr = (dcregs *)dcpdma[unit].p_addr; 395 396 /* 397 * Handle console cases specially. 398 */ 399 if (cn_tab.cn_screen) { 400 if (unit == DCKBD_PORT) { 401 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | 402 LPR_B4800 | DCKBD_PORT; 403 MachEmptyWriteBuffer(); 404 return (0); 405 } else if (unit == DCMOUSE_PORT) { 406 dcaddr->dc_lpr = LPR_RXENAB | LPR_B4800 | LPR_OPAR | 407 LPR_PARENB | LPR_8_BIT_CHAR | DCMOUSE_PORT; 408 MachEmptyWriteBuffer(); 409 return (0); 410 } 411 } else if (tp->t_dev == cn_tab.cn_dev) { 412 dcaddr->dc_lpr = LPR_RXENAB | LPR_8_BIT_CHAR | 413 LPR_B9600 | unit; 414 MachEmptyWriteBuffer(); 415 return (0); 416 } 417 if (ospeed == 0) { 418 (void) dcmctl(unit, 0, DMSET); /* hang up line */ 419 return (0); 420 } 421 lpr = LPR_RXENAB | ospeed | (unit & 03); 422 if ((cflag & CSIZE) == CS7) 423 lpr |= LPR_7_BIT_CHAR; 424 else 425 lpr |= LPR_8_BIT_CHAR; 426 if (cflag & PARENB) 427 lpr |= LPR_PARENB; 428 if (cflag & PARODD) 429 lpr |= LPR_OPAR; 430 if (cflag & CSTOPB) 431 lpr |= LPR_2_STOP; 432 dcaddr->dc_lpr = lpr; 433 MachEmptyWriteBuffer(); 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 ((dcregs *)dp->p_addr)->dc_tcr &= ~(1 << (minor(tp->t_dev) & 03)); 573 MachEmptyWriteBuffer(); 574 DELAY(10); 575 } 576 } 577 578 void 579 dcstart(tp) 580 register struct tty *tp; 581 { 582 register struct pdma *dp; 583 register dcregs *dcaddr; 584 register int cc; 585 int s; 586 587 dp = (struct pdma *)tp->t_addr; 588 dcaddr = (dcregs *)dp->p_addr; 589 s = spltty(); 590 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 591 goto out; 592 if (tp->t_outq.c_cc <= tp->t_lowat) { 593 if (tp->t_state & TS_ASLEEP) { 594 tp->t_state &= ~TS_ASLEEP; 595 wakeup((caddr_t)&tp->t_outq); 596 } 597 selwakeup(&tp->t_wsel); 598 } 599 if (tp->t_outq.c_cc == 0) 600 goto out; 601 /* handle console specially */ 602 if (tp == &dc_tty[DCKBD_PORT] && cn_tab.cn_screen) { 603 while (tp->t_outq.c_cc > 0) { 604 cc = getc(&tp->t_outq) & 0x7f; 605 cnputc(cc); 606 } 607 /* 608 * After we flush the output queue we may need to wake 609 * up the process that made the output. 610 */ 611 if (tp->t_outq.c_cc <= tp->t_lowat) { 612 if (tp->t_state & TS_ASLEEP) { 613 tp->t_state &= ~TS_ASLEEP; 614 wakeup((caddr_t)&tp->t_outq); 615 } 616 selwakeup(&tp->t_wsel); 617 } 618 goto out; 619 } 620 if (tp->t_flags & (RAW|LITOUT)) 621 cc = ndqb(&tp->t_outq, 0); 622 else { 623 cc = ndqb(&tp->t_outq, 0200); 624 if (cc == 0) { 625 cc = getc(&tp->t_outq); 626 timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6); 627 tp->t_state |= TS_TIMEOUT; 628 goto out; 629 } 630 } 631 tp->t_state |= TS_BUSY; 632 dp->p_end = dp->p_mem = tp->t_outq.c_cf; 633 dp->p_end += cc; 634 dcaddr->dc_tcr |= 1 << (minor(tp->t_dev) & 03); 635 MachEmptyWriteBuffer(); 636 out: 637 splx(s); 638 } 639 640 /* 641 * Stop output on a line. 642 */ 643 /*ARGSUSED*/ 644 dcstop(tp, flag) 645 register struct tty *tp; 646 { 647 register struct pdma *dp; 648 register int s; 649 650 dp = (struct pdma *)tp->t_addr; 651 s = spltty(); 652 if (tp->t_state & TS_BUSY) { 653 dp->p_end = dp->p_mem; 654 if (!(tp->t_state & TS_TTSTOP)) 655 tp->t_state |= TS_FLUSH; 656 } 657 splx(s); 658 } 659 660 dcmctl(dev, bits, how) 661 dev_t dev; 662 int bits, how; 663 { 664 register dcregs *dcaddr; 665 register int unit, mbits; 666 int b, s; 667 register int msr; 668 669 unit = minor(dev); 670 b = 1 << (unit & 03); 671 dcaddr = (dcregs *)dcpdma[unit].p_addr; 672 s = spltty(); 673 /* only channel 2 has modem control (what about line 3?) */ 674 mbits = DML_DTR | DML_DSR | DML_CAR; 675 switch (unit & 03) { 676 case 2: 677 mbits = 0; 678 if (dcaddr->dc_tcr & TCR_DTR2) 679 mbits |= DML_DTR; 680 msr = dcaddr->dc_msr; 681 if (msr & MSR_CD2) 682 mbits |= DML_CAR; 683 if (msr & MSR_DSR2) { 684 if (pmax_boardtype == DS_PMAX) 685 mbits |= DML_CAR | DML_DSR; 686 else 687 mbits |= DML_DSR; 688 } 689 break; 690 691 case 3: 692 if (pmax_boardtype != DS_PMAX) { 693 mbits = 0; 694 if (dcaddr->dc_tcr & TCR_DTR3) 695 mbits |= DML_DTR; 696 msr = dcaddr->dc_msr; 697 if (msr & MSR_CD3) 698 mbits |= DML_CAR; 699 if (msr & MSR_DSR3) 700 mbits |= DML_DSR; 701 } 702 } 703 switch (how) { 704 case DMSET: 705 mbits = bits; 706 break; 707 708 case DMBIS: 709 mbits |= bits; 710 break; 711 712 case DMBIC: 713 mbits &= ~bits; 714 break; 715 716 case DMGET: 717 (void) splx(s); 718 return (mbits); 719 } 720 switch (unit & 03) { 721 case 2: 722 if (mbits & DML_DTR) 723 dcaddr->dc_tcr |= TCR_DTR2; 724 else 725 dcaddr->dc_tcr &= ~TCR_DTR2; 726 break; 727 728 case 3: 729 if (pmax_boardtype != DS_PMAX) { 730 if (mbits & DML_DTR) 731 dcaddr->dc_tcr |= TCR_DTR3; 732 else 733 dcaddr->dc_tcr &= ~TCR_DTR3; 734 } 735 } 736 if ((mbits & DML_DTR) && (dcsoftCAR[unit >> 2] & b)) 737 dc_tty[unit].t_state |= TS_CARR_ON; 738 (void) splx(s); 739 return (mbits); 740 } 741 742 /* 743 * This is called by timeout() periodically. 744 * Check to see if modem status bits have changed. 745 */ 746 void 747 dcscan(arg) 748 void *arg; 749 { 750 register dcregs *dcaddr; 751 register struct tty *tp; 752 register int i, bit, car; 753 int s; 754 755 s = spltty(); 756 /* only channel 2 has modem control (what about line 3?) */ 757 dcaddr = (dcregs *)dcpdma[i = 2].p_addr; 758 tp = &dc_tty[i]; 759 bit = TCR_DTR2; 760 if (dcsoftCAR[i >> 2] & bit) 761 car = 1; 762 else 763 car = dcaddr->dc_msr & MSR_DSR2; 764 if (car) { 765 /* carrier present */ 766 if (!(tp->t_state & TS_CARR_ON)) 767 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 768 } else if ((tp->t_state & TS_CARR_ON) && 769 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 770 dcaddr->dc_tcr &= ~bit; 771 splx(s); 772 timeout(dcscan, (void *)0, hz); 773 } 774 775 /* 776 * ---------------------------------------------------------------------------- 777 * 778 * dcGetc -- 779 * 780 * Read a character from a serial line. 781 * 782 * Results: 783 * A character read from the serial port. 784 * 785 * Side effects: 786 * None. 787 * 788 * ---------------------------------------------------------------------------- 789 */ 790 int 791 dcGetc(dev) 792 dev_t dev; 793 { 794 register dcregs *dcaddr; 795 register int c; 796 int s; 797 798 dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr; 799 if (!dcaddr) 800 return (0); 801 s = spltty(); 802 for (;;) { 803 if (!(dcaddr->dc_csr & CSR_RDONE)) 804 continue; 805 c = dcaddr->dc_rbuf; 806 DELAY(10); 807 if (((c >> 8) & 03) == (minor(dev) & 03)) 808 break; 809 } 810 splx(s); 811 return (c & 0xff); 812 } 813 814 /* 815 * Send a char on a port, non interrupt driven. 816 */ 817 void 818 dcPutc(dev, c) 819 dev_t dev; 820 int c; 821 { 822 register dcregs *dcaddr; 823 register u_short tcr; 824 register int timeout; 825 int s, line; 826 827 s = spltty(); 828 829 dcaddr = (dcregs *)dcpdma[minor(dev)].p_addr; 830 tcr = dcaddr->dc_tcr; 831 dcaddr->dc_tcr = tcr | (1 << minor(dev)); 832 MachEmptyWriteBuffer(); 833 DELAY(10); 834 while (1) { 835 /* 836 * Wait for transmitter to be not busy. 837 */ 838 timeout = 1000000; 839 while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0) 840 timeout--; 841 if (timeout == 0) { 842 printf("dcPutc: timeout waiting for CSR_TRDY\n"); 843 break; 844 } 845 line = (dcaddr->dc_csr >> 8) & 3; 846 /* 847 * Check to be sure its the right port. 848 */ 849 if (line != minor(dev)) { 850 tcr |= 1 << line; 851 dcaddr->dc_tcr &= ~(1 << line); 852 MachEmptyWriteBuffer(); 853 DELAY(10); 854 continue; 855 } 856 /* 857 * Start sending the character. 858 */ 859 dcaddr->dc_tdr = dc_brk[0] | (c & 0xff); 860 MachEmptyWriteBuffer(); 861 DELAY(10); 862 /* 863 * Wait for character to be sent. 864 */ 865 while (1) { 866 /* 867 * cc -O bug: this code produces and infinite loop! 868 * while (!(dcaddr->dc_csr & CSR_TRDY)) 869 * ; 870 */ 871 timeout = 1000000; 872 while (!(dcaddr->dc_csr & CSR_TRDY) && timeout > 0) 873 timeout--; 874 line = (dcaddr->dc_csr >> 8) & 3; 875 if (line != minor(dev)) { 876 tcr |= 1 << line; 877 dcaddr->dc_tcr &= ~(1 << line); 878 MachEmptyWriteBuffer(); 879 DELAY(10); 880 continue; 881 } 882 dcaddr->dc_tcr &= ~(1 << minor(dev)); 883 MachEmptyWriteBuffer(); 884 DELAY(10); 885 break; 886 } 887 break; 888 } 889 /* 890 * Enable interrupts for other lines which became ready. 891 */ 892 if (tcr & 0xF) { 893 dcaddr->dc_tcr = tcr; 894 MachEmptyWriteBuffer(); 895 DELAY(10); 896 } 897 898 splx(s); 899 } 900 #endif /* NDC */ 901