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