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