1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)dz.c 7.14 (Berkeley) 05/16/91 7 */ 8 9 #include "dz.h" 10 #if NDZ > 0 11 /* 12 * DZ-11/DZ-32 Driver 13 * 14 * This driver mimics dh.c; see it for explanation of common code. 15 */ 16 #include "sys/param.h" 17 #include "sys/systm.h" 18 #include "sys/ioctl.h" 19 #include "sys/tty.h" 20 #include "sys/user.h" 21 #include "sys/proc.h" 22 #include "sys/map.h" 23 #include "sys/buf.h" 24 #include "sys/vm.h" 25 #include "sys/conf.h" 26 #include "sys/file.h" 27 #include "sys/uio.h" 28 #include "sys/kernel.h" 29 #include "sys/syslog.h" 30 31 #include "pdma.h" 32 #include "ubavar.h" 33 #include "dzreg.h" 34 #include "../include/pte.h" 35 36 /* 37 * Driver information for auto-configuration stuff. 38 */ 39 int dzprobe(), dzattach(), dzrint(); 40 struct uba_device *dzinfo[NDZ]; 41 u_short dzstd[] = { 0 }; 42 struct uba_driver dzdriver = 43 { dzprobe, 0, dzattach, 0, dzstd, "dz", dzinfo }; 44 45 #define NDZLINE (NDZ*8) 46 #define FASTTIMER (hz/30) /* rate to drain silos, when in use */ 47 48 int dzstart(), dzxint(), dzdma(); 49 int ttrstrt(); 50 struct tty dz_tty[NDZLINE]; 51 int dz_cnt = { NDZLINE }; 52 int dzact; 53 int dzsilos; /* mask of dz's with silo in use */ 54 int dzchars[NDZ]; /* recent input count */ 55 int dzrate[NDZ]; /* smoothed input count */ 56 int dztimerintvl; /* time interval for dztimer */ 57 int dzhighrate = 100; /* silo on if dzchars > dzhighrate */ 58 int dzlowrate = 75; /* silo off if dzrate < dzlowrate */ 59 60 #define dzwait(x) while (((x)->dzlcs & DZ_ACK) == 0) 61 62 /* 63 * Software copy of dzbrk since it isn't readable 64 */ 65 char dz_brk[NDZ]; 66 char dzsoftCAR[NDZ]; 67 char dz_lnen[NDZ]; /* saved line enable bits for DZ32 */ 68 69 /* 70 * The dz11 doesn't interrupt on carrier transitions, so 71 * we have to use a timer to watch it. 72 */ 73 char dz_timer; /* timer started? */ 74 75 /* 76 * Pdma structures for fast output code 77 */ 78 struct pdma dzpdma[NDZLINE]; 79 80 struct speedtab dzspeedtab[] = { 81 0, 0, 82 50, 020, 83 75, 021, 84 110, 022, 85 134, 023, 86 150, 024, 87 300, 025, 88 600, 026, 89 1200, 027, 90 1800, 030, 91 2400, 032, 92 4800, 034, 93 9600, 036, 94 19200, 037, 95 EXTA, 037, 96 -1, -1 97 }; 98 99 #ifndef PORTSELECTOR 100 #define ISPEED TTYDEF_SPEED 101 #define LFLAG TTYDEF_LFLAG 102 #else 103 #define ISPEED B4800 104 #define LFLAG (TTYDEF_LFLAG&~ECHO) 105 #endif 106 107 dzprobe(reg) 108 caddr_t reg; 109 { 110 register int br, cvec; 111 register struct dzdevice *dzaddr = (struct dzdevice *)reg; 112 113 #ifdef lint 114 br = 0; cvec = br; br = cvec; 115 dzrint(0); dzxint((struct tty *)0); 116 #endif 117 dzaddr->dzcsr = DZ_TIE|DZ_MSE|DZ_32; 118 if (dzaddr->dzcsr & DZ_32) 119 dzaddr->dzlnen = 1; 120 else 121 dzaddr->dztcr = 1; /* enable any line */ 122 DELAY(100000); 123 dzaddr->dzcsr = DZ_CLR|DZ_32; /* reset everything */ 124 if (cvec && cvec != 0x200) 125 cvec -= 4; 126 return (sizeof (struct dzdevice)); 127 } 128 129 dzattach(ui) 130 register struct uba_device *ui; 131 { 132 register struct pdma *pdp = &dzpdma[ui->ui_unit*8]; 133 register struct tty *tp = &dz_tty[ui->ui_unit*8]; 134 register int cntr; 135 extern dzscan(); 136 137 for (cntr = 0; cntr < 8; cntr++) { 138 pdp->p_addr = (struct dzdevice *)ui->ui_addr; 139 pdp->p_arg = (int)tp; 140 pdp->p_fcn = dzxint; 141 pdp++, tp++; 142 } 143 dzsoftCAR[ui->ui_unit] = ui->ui_flags; 144 if (dz_timer == 0) { 145 dz_timer++; 146 timeout(dzscan, (caddr_t)0, hz); 147 dztimerintvl = FASTTIMER; 148 } 149 } 150 151 /*ARGSUSED*/ 152 dzopen(dev, flag) 153 dev_t dev; 154 { 155 register struct tty *tp; 156 register int unit; 157 int error = 0, dzparam(); 158 159 unit = minor(dev); 160 if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) 161 return (ENXIO); 162 tp = &dz_tty[unit]; 163 tp->t_addr = (caddr_t)&dzpdma[unit]; 164 tp->t_oproc = dzstart; 165 tp->t_param = dzparam; 166 tp->t_dev = dev; 167 if ((tp->t_state & TS_ISOPEN) == 0) { 168 tp->t_state |= TS_WOPEN; 169 ttychars(tp); 170 #ifndef PORTSELECTOR 171 if (tp->t_ispeed == 0) { 172 #endif 173 tp->t_iflag = TTYDEF_IFLAG; 174 tp->t_oflag = TTYDEF_OFLAG; 175 tp->t_cflag = TTYDEF_CFLAG; 176 tp->t_lflag = LFLAG; 177 tp->t_ispeed = tp->t_ospeed = ISPEED; 178 #ifdef PORTSELECTOR 179 tp->t_cflag |= HUPCL; 180 #else 181 } 182 #endif 183 dzparam(tp, &tp->t_termios); 184 ttsetwater(tp); 185 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 186 return (EBUSY); 187 (void) dzmctl(dev, DZ_ON, DMSET); 188 (void) spl5(); 189 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 190 (tp->t_state & TS_CARR_ON) == 0) { 191 tp->t_state |= TS_WOPEN; 192 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 193 ttopen, 0)) 194 break; 195 } 196 (void) spl0(); 197 if (error) 198 return (error); 199 return ((*linesw[tp->t_line].l_open)(dev, tp)); 200 } 201 202 /*ARGSUSED*/ 203 dzclose(dev, flag, mode, p) 204 dev_t dev; 205 int flag, mode; 206 struct proc *p; 207 { 208 register struct tty *tp; 209 register int unit; 210 register struct dzdevice *dzaddr; 211 int dz; 212 213 unit = minor(dev); 214 dz = unit >> 3; 215 tp = &dz_tty[unit]; 216 (*linesw[tp->t_line].l_close)(tp, flag); 217 dzaddr = dzpdma[unit].p_addr; 218 if (dzaddr->dzcsr&DZ_32) 219 (void) dzmctl(dev, DZ_BRK, DMBIC); 220 else 221 dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07))); 222 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 223 (tp->t_state&TS_ISOPEN) == 0) 224 (void) dzmctl(dev, DZ_OFF, DMSET); 225 return (ttyclose(tp)); 226 } 227 228 dzread(dev, uio, flag) 229 dev_t dev; 230 struct uio *uio; 231 { 232 register struct tty *tp; 233 234 tp = &dz_tty[minor(dev)]; 235 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 236 } 237 238 dzwrite(dev, uio, flag) 239 dev_t dev; 240 struct uio *uio; 241 { 242 register struct tty *tp; 243 244 tp = &dz_tty[minor(dev)]; 245 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 246 } 247 248 /*ARGSUSED*/ 249 dzrint(dz) 250 int dz; 251 { 252 register struct tty *tp; 253 register int c, cc; 254 register struct dzdevice *dzaddr; 255 register struct tty *tp0; 256 register int unit; 257 int overrun = 0; 258 259 if ((dzact & (1<<dz)) == 0) 260 return; 261 unit = dz * 8; 262 dzaddr = dzpdma[unit].p_addr; 263 tp0 = &dz_tty[unit]; 264 dzaddr->dzcsr &= ~(DZ_RIE|DZ_MIE); /* the manual says this song */ 265 dzaddr->dzcsr |= DZ_RIE|DZ_MIE; /* and dance is necessary */ 266 while (dzaddr->dzcsr & DZ_MSC) { /* DZ32 modem change interrupt */ 267 c = dzaddr->dzmtsr; 268 tp = tp0 + (c&7); 269 if (tp >= &dz_tty[dz_cnt]) 270 break; 271 dzaddr->dzlcs = c&7; /* get status of modem lines */ 272 dzwait(dzaddr); /* wait for them */ 273 if (c & DZ_CD) /* carrier status change? */ 274 if (dzaddr->dzlcs & DZ_CD) { /* carrier up? */ 275 /* carrier present */ 276 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 277 } else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 278 dzaddr->dzlcs = DZ_ACK|(c&7); 279 } 280 while ((c = dzaddr->dzrbuf) < 0) { /* char present */ 281 cc = c&0xff; 282 dzchars[dz]++; 283 tp = tp0 + ((c>>8)&07); 284 if (tp >= &dz_tty[dz_cnt]) 285 continue; 286 if ((tp->t_state & TS_ISOPEN) == 0) { 287 wakeup((caddr_t)&tp->t_rawq); 288 #ifdef PORTSELECTOR 289 if ((tp->t_state&TS_WOPEN) == 0) 290 #endif 291 continue; 292 } 293 if (c&DZ_FE) 294 cc |= TTY_FE; 295 if (c&DZ_DO && overrun == 0) { 296 log(LOG_WARNING, "dz%d,%d: silo overflow\n", dz, (c>>8)&7); 297 overrun = 1; 298 } 299 if (c&DZ_PE) 300 cc |= TTY_PE; 301 (*linesw[tp->t_line].l_rint)(cc, tp); 302 } 303 } 304 305 /*ARGSUSED*/ 306 dzioctl(dev, cmd, data, flag) 307 dev_t dev; 308 caddr_t data; 309 { 310 register struct tty *tp; 311 register int unit = minor(dev); 312 register int dz = unit >> 3; 313 register struct dzdevice *dzaddr; 314 int error; 315 316 tp = &dz_tty[unit]; 317 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 318 if (error >= 0) 319 return (error); 320 error = ttioctl(tp, cmd, data, flag); 321 if (error >= 0) 322 return (error); 323 324 switch (cmd) { 325 326 case TIOCSBRK: 327 dzaddr = ((struct pdma *)(tp->t_addr))->p_addr; 328 if (dzaddr->dzcsr&DZ_32) 329 (void) dzmctl(dev, DZ_BRK, DMBIS); 330 else 331 dzaddr->dzbrk = (dz_brk[dz] |= 1 << (unit&07)); 332 break; 333 334 case TIOCCBRK: 335 dzaddr = ((struct pdma *)(tp->t_addr))->p_addr; 336 if (dzaddr->dzcsr&DZ_32) 337 (void) dzmctl(dev, DZ_BRK, DMBIC); 338 else 339 dzaddr->dzbrk = (dz_brk[dz] &= ~(1 << (unit&07))); 340 break; 341 342 case TIOCSDTR: 343 (void) dzmctl(dev, DZ_DTR|DZ_RTS, DMBIS); 344 break; 345 346 case TIOCCDTR: 347 (void) dzmctl(dev, DZ_DTR|DZ_RTS, DMBIC); 348 break; 349 350 case TIOCMSET: 351 (void) dzmctl(dev, dmtodz(*(int *)data), DMSET); 352 break; 353 354 case TIOCMBIS: 355 (void) dzmctl(dev, dmtodz(*(int *)data), DMBIS); 356 break; 357 358 case TIOCMBIC: 359 (void) dzmctl(dev, dmtodz(*(int *)data), DMBIC); 360 break; 361 362 case TIOCMGET: 363 *(int *)data = dztodm(dzmctl(dev, 0, DMGET)); 364 break; 365 366 default: 367 return (ENOTTY); 368 } 369 return (0); 370 } 371 372 dmtodz(bits) 373 register int bits; 374 { 375 register int b; 376 377 b = (bits >>1) & 0370; 378 if (bits & DML_ST) b |= DZ_ST; 379 if (bits & DML_RTS) b |= DZ_RTS; 380 if (bits & DML_DTR) b |= DZ_DTR; 381 if (bits & DML_LE) b |= DZ_LE; 382 return(b); 383 } 384 385 dztodm(bits) 386 register int bits; 387 { 388 register int b; 389 390 b = (bits << 1) & 0360; 391 if (bits & DZ_DSR) b |= DML_DSR; 392 if (bits & DZ_DTR) b |= DML_DTR; 393 if (bits & DZ_ST) b |= DML_ST; 394 if (bits & DZ_RTS) b |= DML_RTS; 395 return(b); 396 } 397 398 dzparam(tp, t) 399 register struct tty *tp; 400 register struct termios *t; 401 { 402 register struct dzdevice *dzaddr; 403 register int lpr; 404 register int cflag = t->c_cflag; 405 int unit = minor(tp->t_dev); 406 int ospeed = ttspeedtab(t->c_ospeed, dzspeedtab); 407 408 /* check requested parameters */ 409 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed) || 410 (cflag&CSIZE) == CS5 || (cflag&CSIZE) == CS6) 411 return(EINVAL); 412 /* and copy to tty */ 413 tp->t_ispeed = t->c_ispeed; 414 tp->t_ospeed = t->c_ospeed; 415 tp->t_cflag = cflag; 416 417 dzaddr = dzpdma[unit].p_addr; 418 if (dzsilos & (1 << (unit >> 3))) 419 dzaddr->dzcsr = DZ_IEN | DZ_SAE; 420 else 421 dzaddr->dzcsr = DZ_IEN; 422 dzact |= (1<<(unit>>3)); 423 if (ospeed == 0) 424 (void) dzmctl(unit, DZ_OFF, DMSET); /* hang up line */ 425 else { 426 lpr = (ospeed<<8) | (unit & 07); 427 if ((cflag&CSIZE) == CS7) 428 lpr |= BITS7; 429 else 430 lpr |= BITS8; 431 if (cflag&PARENB) 432 lpr |= PENABLE; 433 if (cflag&PARODD) 434 lpr |= OPAR; 435 if (cflag&CSTOPB) 436 lpr |= TWOSB; 437 dzaddr->dzlpr = lpr; 438 } 439 return(0); 440 } 441 442 dzxint(tp) 443 register struct tty *tp; 444 { 445 register struct pdma *dp; 446 register dz, unit; 447 448 dp = (struct pdma *)tp->t_addr; 449 tp->t_state &= ~TS_BUSY; 450 if (tp->t_state & TS_FLUSH) 451 tp->t_state &= ~TS_FLUSH; 452 else { 453 ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf); 454 dp->p_end = dp->p_mem = tp->t_outq.c_cf; 455 } 456 if (tp->t_line) 457 (*linesw[tp->t_line].l_start)(tp); 458 else 459 dzstart(tp); 460 dz = minor(tp->t_dev) >> 3; 461 unit = minor(tp->t_dev) & 7; 462 if (tp->t_outq.c_cc == 0 || (tp->t_state&TS_BUSY)==0) 463 if (dp->p_addr->dzcsr & DZ_32) 464 dp->p_addr->dzlnen = (dz_lnen[dz] &= ~(1<<unit)); 465 else 466 dp->p_addr->dztcr &= ~(1<<unit); 467 } 468 469 dzstart(tp) 470 register struct tty *tp; 471 { 472 register struct pdma *dp; 473 register struct dzdevice *dzaddr; 474 register int cc; 475 int s, dz, unit; 476 477 dp = (struct pdma *)tp->t_addr; 478 dzaddr = dp->p_addr; 479 s = spl5(); 480 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 481 goto out; 482 if (tp->t_outq.c_cc <= tp->t_lowat) { 483 if (tp->t_state&TS_ASLEEP) { 484 tp->t_state &= ~TS_ASLEEP; 485 wakeup((caddr_t)&tp->t_outq); 486 } 487 if (tp->t_wsel) { 488 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 489 tp->t_wsel = 0; 490 tp->t_state &= ~TS_WCOLL; 491 } 492 } 493 if (tp->t_outq.c_cc == 0) 494 goto out; 495 if (tp->t_flags & (RAW|LITOUT)) 496 cc = ndqb(&tp->t_outq, 0); 497 else { 498 cc = ndqb(&tp->t_outq, 0200); 499 if (cc == 0) { 500 cc = getc(&tp->t_outq); 501 timeout(ttrstrt, (caddr_t)tp, (cc&0x7f) + 6); 502 tp->t_state |= TS_TIMEOUT; 503 goto out; 504 } 505 } 506 tp->t_state |= TS_BUSY; 507 dp->p_end = dp->p_mem = tp->t_outq.c_cf; 508 dp->p_end += cc; 509 dz = minor(tp->t_dev) >> 3; 510 unit = minor(tp->t_dev) & 7; 511 if (dzaddr->dzcsr & DZ_32) 512 dzaddr->dzlnen = (dz_lnen[dz] |= (1<<unit)); 513 else 514 dzaddr->dztcr |= (1<<unit); 515 out: 516 splx(s); 517 } 518 519 /* 520 * Stop output on a line. 521 */ 522 /*ARGSUSED*/ 523 dzstop(tp, flag) 524 register struct tty *tp; 525 { 526 register struct pdma *dp; 527 register int s; 528 529 dp = (struct pdma *)tp->t_addr; 530 s = spl5(); 531 if (tp->t_state & TS_BUSY) { 532 dp->p_end = dp->p_mem; 533 if ((tp->t_state&TS_TTSTOP)==0) 534 tp->t_state |= TS_FLUSH; 535 } 536 splx(s); 537 } 538 539 dzmctl(dev, bits, how) 540 dev_t dev; 541 int bits, how; 542 { 543 register struct dzdevice *dzaddr; 544 register int unit, mbits; 545 int b, s; 546 547 unit = minor(dev); 548 b = 1<<(unit&7); 549 dzaddr = dzpdma[unit].p_addr; 550 s = spl5(); 551 if (dzaddr->dzcsr & DZ_32) { 552 dzwait(dzaddr) 553 DELAY(100); /* IS 100 TOO MUCH? */ 554 dzaddr->dzlcs = unit&7; 555 DELAY(100); 556 dzwait(dzaddr) 557 DELAY(100); 558 mbits = dzaddr->dzlcs; 559 mbits &= 0177770; 560 } else { 561 mbits = (dzaddr->dzdtr & b) ? DZ_DTR : 0; 562 mbits |= (dzaddr->dzmsr & b) ? DZ_CD : 0; 563 mbits |= (dzaddr->dztbuf & b) ? DZ_RI : 0; 564 } 565 switch (how) { 566 case DMSET: 567 mbits = bits; 568 break; 569 570 case DMBIS: 571 mbits |= bits; 572 break; 573 574 case DMBIC: 575 mbits &= ~bits; 576 break; 577 578 case DMGET: 579 (void) splx(s); 580 return(mbits); 581 } 582 if (dzaddr->dzcsr & DZ_32) { 583 mbits |= DZ_ACK|(unit&7); 584 dzaddr->dzlcs = mbits; 585 } else { 586 if (mbits & DZ_DTR) 587 dzaddr->dzdtr |= b; 588 else 589 dzaddr->dzdtr &= ~b; 590 } 591 if (mbits & DZ_DTR && dzsoftCAR[unit >> 3] & b) 592 dz_tty[unit].t_state |= TS_CARR_ON; 593 (void) splx(s); 594 return(mbits); 595 } 596 597 int dztransitions, dzfasttimers; /*DEBUG*/ 598 dzscan() 599 { 600 register i; 601 register struct dzdevice *dzaddr; 602 register bit; 603 register struct tty *tp; 604 register car; 605 int olddzsilos = dzsilos; 606 int dztimer(); 607 608 for (i = 0; i < dz_cnt ; i++) { 609 dzaddr = dzpdma[i].p_addr; 610 if (dzaddr == 0) 611 continue; 612 tp = &dz_tty[i]; 613 bit = 1<<(i&07); 614 car = 0; 615 if (dzsoftCAR[i>>3]&bit) 616 car = 1; 617 else if (dzaddr->dzcsr & DZ_32) { 618 dzaddr->dzlcs = i&07; 619 dzwait(dzaddr); 620 car = dzaddr->dzlcs & DZ_CD; 621 } else 622 car = dzaddr->dzmsr&bit; 623 if (car) { 624 /* carrier present */ 625 if ((tp->t_state & TS_CARR_ON) == 0) 626 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 627 } else if ((tp->t_state&TS_CARR_ON) && 628 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 629 dzaddr->dzdtr &= ~bit; 630 } 631 for (i = 0; i < NDZ; i++) { 632 ave(dzrate[i], dzchars[i], 8); 633 if (dzchars[i] > dzhighrate && ((dzsilos & (1 << i)) == 0)) { 634 dzpdma[i << 3].p_addr->dzcsr = DZ_IEN | DZ_SAE; 635 dzsilos |= (1 << i); 636 dztransitions++; /*DEBUG*/ 637 } else if ((dzsilos & (1 << i)) && (dzrate[i] < dzlowrate)) { 638 dzpdma[i << 3].p_addr->dzcsr = DZ_IEN; 639 dzsilos &= ~(1 << i); 640 } 641 dzchars[i] = 0; 642 } 643 if (dzsilos && !olddzsilos) 644 timeout(dztimer, (caddr_t)0, dztimerintvl); 645 timeout(dzscan, (caddr_t)0, hz); 646 } 647 648 dztimer() 649 { 650 register int dz; 651 register int s; 652 653 if (dzsilos == 0) 654 return; 655 s = spl5(); 656 dzfasttimers++; /*DEBUG*/ 657 for (dz = 0; dz < NDZ; dz++) 658 if (dzsilos & (1 << dz)) 659 dzrint(dz); 660 splx(s); 661 timeout(dztimer, (caddr_t) 0, dztimerintvl); 662 } 663 664 /* 665 * Reset state of driver if UBA reset was necessary. 666 * Reset parameters and restart transmission on open lines. 667 */ 668 dzreset(uban) 669 int uban; 670 { 671 register int unit; 672 register struct tty *tp; 673 register struct uba_device *ui; 674 675 for (unit = 0; unit < NDZLINE; unit++) { 676 ui = dzinfo[unit >> 3]; 677 if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0) 678 continue; 679 if (unit%8 == 0) 680 printf(" dz%d", unit>>3); 681 tp = &dz_tty[unit]; 682 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 683 dzparam(unit); 684 (void) dzmctl(unit, DZ_ON, DMSET); 685 tp->t_state &= ~TS_BUSY; 686 dzstart(tp); 687 } 688 } 689 } 690 #endif 691