1 /* 2 * Copyright (c) 1985 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 * @(#)dhu.c 4.8 (Berkeley) 02/17/86 7 */ 8 9 /* 10 * based on dh.c 6.3 84/03/15 11 * and on dmf.c 6.2 84/02/16 12 * 13 * Dave Johnson, Brown University Computer Science 14 * ddj%brown@csnet-relay 15 */ 16 17 #include "dhu.h" 18 #if NDHU > 0 19 /* 20 * DHU-11 driver 21 */ 22 #include "../machine/pte.h" 23 24 #include "bk.h" 25 #include "param.h" 26 #include "conf.h" 27 #include "dir.h" 28 #include "user.h" 29 #include "proc.h" 30 #include "ioctl.h" 31 #include "tty.h" 32 #include "map.h" 33 #include "buf.h" 34 #include "vm.h" 35 #include "kernel.h" 36 #include "syslog.h" 37 38 #include "uba.h" 39 #include "ubareg.h" 40 #include "ubavar.h" 41 #include "dhureg.h" 42 43 #include "bkmac.h" 44 #include "clist.h" 45 #include "file.h" 46 #include "uio.h" 47 48 /* 49 * Definition of the driver for the auto-configuration program. 50 */ 51 int dhuprobe(), dhuattach(), dhurint(), dhuxint(); 52 struct uba_device *dhuinfo[NDHU]; 53 u_short dhustd[] = { 160440, 160500, 0 }; /* some common addresses */ 54 struct uba_driver dhudriver = 55 { dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo }; 56 57 #define NDHULINE (NDHU*16) 58 59 #define UNIT(x) (minor(x)) 60 61 #ifndef PORTSELECTOR 62 #define ISPEED B9600 63 #define IFLAGS (EVENP|ODDP|ECHO) 64 #else 65 #define ISPEED B4800 66 #define IFLAGS (EVENP|ODDP) 67 #endif 68 69 /* 70 * default receive silo timeout value -- valid values are 2..255 71 * number of ms. to delay between first char received and receive interrupt 72 * 73 * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0 74 */ 75 #define DHU_DEF_TIMO 20 76 77 /* 78 * Other values for silo timeout register defined here but not used: 79 * receive interrupt only on modem control or silo alarm (3/4 full) 80 */ 81 #define DHU_POLL_TIMO 0 82 /* 83 * receive interrupt immediately on receive character 84 */ 85 #define DHU_NO_TIMO 1 86 87 /* 88 * Local variables for the driver 89 */ 90 /* 91 * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B". 92 * EXTA => 19200 baud 93 * EXTB => 2000 baud 94 */ 95 char dhu_speeds[] = 96 { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 10, 11, 13, 14, 9 }; 97 98 short dhusoftCAR[NDHU]; 99 100 struct tty dhu_tty[NDHULINE]; 101 int ndhu = NDHULINE; 102 int dhuact; /* mask of active dhu's */ 103 int dhustart(), ttrstrt(); 104 105 /* 106 * The clist space is mapped by the driver onto each UNIBUS. 107 * The UBACVT macro converts a clist space address for unibus uban 108 * into an i/o space address for the DMA routine. 109 */ 110 int dhu_ubinfo[NUBA]; /* info about allocated unibus map */ 111 int cbase[NUBA]; /* base address in unibus map */ 112 #define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) 113 114 /* 115 * Routine for configuration to force a dhu to interrupt. 116 */ 117 /*ARGSUSED*/ 118 dhuprobe(reg) 119 caddr_t reg; 120 { 121 register int br, cvec; /* these are ``value-result'' */ 122 register struct dhudevice *dhuaddr = (struct dhudevice *)reg; 123 int i; 124 125 #ifdef lint 126 br = 0; cvec = br; br = cvec; 127 if (ndhu == 0) ndhu = 1; 128 dhurint(0); dhuxint(0); 129 #endif 130 /* 131 * The basic idea here is: 132 * do a self-test by setting the Master-Reset bit 133 * if this fails, then return 134 * if successful, there will be 8 diagnostic codes in RX FIFO 135 * therefore ask for a Received-Data-Available interrupt 136 * wait for it... 137 * reset the interrupt-enable bit and flush out the diag. codes 138 */ 139 dhuaddr->dhucsr = DHU_CS_MCLR; 140 for (i = 0; i < 1000; i++) { 141 DELAY(10000); 142 if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0) 143 break; 144 } 145 if (dhuaddr->dhucsr&DHU_CS_MCLR) 146 return(0); 147 if (dhuaddr->dhucsr&DHU_CS_DFAIL) 148 return(0); 149 dhuaddr->dhucsr = DHU_CS_RIE; 150 DELAY(1000); 151 dhuaddr->dhucsr = 0; 152 while (dhuaddr->dhurbuf < 0) 153 /* void */; 154 return (sizeof(struct dhudevice)); 155 } 156 157 /* 158 * Routine called to attach a dhu. 159 */ 160 dhuattach(ui) 161 struct uba_device *ui; 162 { 163 164 dhusoftCAR[ui->ui_unit] = ui->ui_flags; 165 cbase[ui->ui_ubanum] = -1; 166 } 167 168 /* 169 * Open a DHU11 line, mapping the clist onto the uba if this 170 * is the first dhu on this uba. Turn on this dhu if this is 171 * the first use of it. 172 */ 173 /*ARGSUSED*/ 174 dhuopen(dev, flag) 175 dev_t dev; 176 { 177 register struct tty *tp; 178 register int unit, dhu; 179 register struct dhudevice *addr; 180 register struct uba_device *ui; 181 int s; 182 183 unit = UNIT(dev); 184 dhu = unit >> 4; 185 if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) 186 return (ENXIO); 187 tp = &dhu_tty[unit]; 188 if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 189 return (EBUSY); 190 addr = (struct dhudevice *)ui->ui_addr; 191 tp->t_addr = (caddr_t)addr; 192 tp->t_oproc = dhustart; 193 /* 194 * While setting up state for this uba and this dhu, 195 * block uba resets which can clear the state. 196 */ 197 s = spl5(); 198 if (cbase[ui->ui_ubanum] == -1) { 199 dhu_ubinfo[ui->ui_ubanum] = 200 uballoc(ui->ui_ubanum, (caddr_t)cfree, 201 nclist*sizeof(struct cblock), 0); 202 cbase[ui->ui_ubanum] = UBAI_ADDR(dhu_ubinfo[ui->ui_ubanum]); 203 } 204 if ((dhuact&(1<<dhu)) == 0) { 205 addr->dhucsr = DHU_SELECT(0) | DHU_IE; 206 addr->dhutimo = DHU_DEF_TIMO; 207 dhuact |= (1<<dhu); 208 /* anything else to configure whole board */ 209 } 210 (void) splx(s); 211 /* 212 * If this is first open, initialize tty state to default. 213 */ 214 if ((tp->t_state&TS_ISOPEN) == 0) { 215 ttychars(tp); 216 #ifndef PORTSELECTOR 217 if (tp->t_ispeed == 0) { 218 #else 219 tp->t_state |= TS_HUPCLS; 220 #endif PORTSELECTOR 221 tp->t_ispeed = ISPEED; 222 tp->t_ospeed = ISPEED; 223 tp->t_flags = IFLAGS; 224 #ifndef PORTSELECTOR 225 } 226 #endif PORTSELECTOR 227 tp->t_dev = dev; 228 dhuparam(unit); 229 } 230 /* 231 * Wait for carrier, then process line discipline specific open. 232 */ 233 s = spl5(); 234 if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 235 (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 236 tp->t_state |= TS_CARR_ON; 237 while ((tp->t_state & TS_CARR_ON) == 0) { 238 tp->t_state |= TS_WOPEN; 239 sleep((caddr_t)&tp->t_rawq, TTIPRI); 240 } 241 (void) splx(s); 242 return ((*linesw[tp->t_line].l_open)(dev, tp)); 243 } 244 245 /* 246 * Close a DHU11 line, turning off the modem control. 247 */ 248 /*ARGSUSED*/ 249 dhuclose(dev, flag) 250 dev_t dev; 251 int flag; 252 { 253 register struct tty *tp; 254 register unit; 255 256 unit = UNIT(dev); 257 tp = &dhu_tty[unit]; 258 (*linesw[tp->t_line].l_close)(tp); 259 (void) dhumctl(unit, DHU_BRK, DMBIC); 260 if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0) 261 #ifdef PORTSELECTOR 262 { 263 extern int wakeup(); 264 265 (void) dhumctl(unit, DHU_OFF, DMSET); 266 /* Hold DTR low for 0.5 seconds */ 267 timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 268 sleep((caddr_t) &tp->t_dev, PZERO); 269 } 270 #else 271 (void) dhumctl(unit, DHU_OFF, DMSET); 272 #endif PORTSELECTOR 273 ttyclose(tp); 274 } 275 276 dhuread(dev, uio) 277 dev_t dev; 278 struct uio *uio; 279 { 280 register struct tty *tp = &dhu_tty[UNIT(dev)]; 281 282 return ((*linesw[tp->t_line].l_read)(tp, uio)); 283 } 284 285 dhuwrite(dev, uio) 286 dev_t dev; 287 struct uio *uio; 288 { 289 register struct tty *tp = &dhu_tty[UNIT(dev)]; 290 291 return ((*linesw[tp->t_line].l_write)(tp, uio)); 292 } 293 294 /* 295 * DHU11 receiver interrupt. 296 */ 297 dhurint(dhu) 298 int dhu; 299 { 300 register struct tty *tp; 301 register c; 302 register struct dhudevice *addr; 303 register struct tty *tp0; 304 register struct uba_device *ui; 305 register line; 306 int overrun = 0; 307 308 ui = dhuinfo[dhu]; 309 if (ui == 0 || ui->ui_alive == 0) 310 return; 311 addr = (struct dhudevice *)ui->ui_addr; 312 tp0 = &dhu_tty[dhu<<4]; 313 /* 314 * Loop fetching characters from the silo for this 315 * dhu until there are no more in the silo. 316 */ 317 while ((c = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 318 line = DHU_RX_LINE(c); 319 tp = tp0 + line; 320 if ((c & DHU_RB_STAT) == DHU_RB_STAT) { 321 /* 322 * modem changed or diag info 323 */ 324 if (c & DHU_RB_DIAG) { 325 /* decode diagnostic messages */ 326 continue; 327 } 328 if (c & DHU_ST_DCD) 329 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 330 else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 331 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 332 (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 333 continue; 334 } 335 if ((tp->t_state&TS_ISOPEN) == 0) { 336 wakeup((caddr_t)&tp->t_rawq); 337 #ifdef PORTSELECTOR 338 if ((tp->t_state&TS_WOPEN) == 0) 339 #endif 340 continue; 341 } 342 if (c & DHU_RB_PE) 343 if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 344 (tp->t_flags&(EVENP|ODDP)) == ODDP) 345 continue; 346 if ((c & DHU_RB_DO) && overrun == 0) { 347 log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 348 overrun = 1; 349 } 350 if (c & DHU_RB_FE) 351 /* 352 * At framing error (break) generate 353 * a null (in raw mode, for getty), or a 354 * interrupt (in cooked/cbreak mode). 355 */ 356 if (tp->t_flags&RAW) 357 c = 0; 358 else 359 c = tp->t_intrc; 360 #if NBK > 0 361 if (tp->t_line == NETLDISC) { 362 c &= 0x7f; 363 BKINPUT(c, tp); 364 } else 365 #endif 366 (*linesw[tp->t_line].l_rint)(c, tp); 367 } 368 } 369 370 /* 371 * Ioctl for DHU11. 372 */ 373 /*ARGSUSED*/ 374 dhuioctl(dev, cmd, data, flag) 375 caddr_t data; 376 { 377 register struct tty *tp; 378 register int unit = UNIT(dev); 379 register dhu = unit>>4; 380 register bit = (1<<(unit&0xf)); 381 int error; 382 383 tp = &dhu_tty[unit]; 384 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 385 if (error >= 0) 386 return (error); 387 error = ttioctl(tp, cmd, data, flag); 388 if (error >= 0) { 389 if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET || 390 cmd == TIOCLBIC || cmd == TIOCLBIS) 391 dhuparam(unit); 392 return (error); 393 } 394 395 switch (cmd) { 396 case TIOCSBRK: 397 (void) dhumctl(unit, DHU_BRK, DMBIS); 398 break; 399 400 case TIOCCBRK: 401 (void) dhumctl(unit, DHU_BRK, DMBIC); 402 break; 403 404 case TIOCSDTR: 405 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 406 break; 407 408 case TIOCCDTR: 409 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 410 break; 411 412 case TIOCMSET: 413 (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 414 break; 415 416 case TIOCMBIS: 417 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 418 break; 419 420 case TIOCMBIC: 421 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 422 break; 423 424 case TIOCMGET: 425 *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 426 break; 427 default: 428 return (ENOTTY); 429 } 430 return (0); 431 } 432 433 dmtodhu(bits) 434 register int bits; 435 { 436 register int b = 0; 437 438 if (bits & DML_RTS) b |= DHU_RTS; 439 if (bits & DML_DTR) b |= DHU_DTR; 440 if (bits & DML_LE) b |= DHU_LE; 441 return(b); 442 } 443 444 dhutodm(bits) 445 register int bits; 446 { 447 register int b = 0; 448 449 if (bits & DHU_DSR) b |= DML_DSR; 450 if (bits & DHU_RNG) b |= DML_RNG; 451 if (bits & DHU_CAR) b |= DML_CAR; 452 if (bits & DHU_CTS) b |= DML_CTS; 453 if (bits & DHU_RTS) b |= DML_RTS; 454 if (bits & DHU_DTR) b |= DML_DTR; 455 if (bits & DHU_LE) b |= DML_LE; 456 return(b); 457 } 458 459 460 /* 461 * Set parameters from open or stty into the DHU hardware 462 * registers. 463 */ 464 dhuparam(unit) 465 register int unit; 466 { 467 register struct tty *tp; 468 register struct dhudevice *addr; 469 register int lpar; 470 int s; 471 472 tp = &dhu_tty[unit]; 473 addr = (struct dhudevice *)tp->t_addr; 474 /* 475 * Block interrupts so parameters will be set 476 * before the line interrupts. 477 */ 478 s = spl5(); 479 if ((tp->t_ispeed) == 0) { 480 tp->t_state |= TS_HUPCLS; 481 (void)dhumctl(unit, DHU_OFF, DMSET); 482 splx(s); 483 return; 484 } 485 lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8); 486 if ((tp->t_ispeed) == B134) 487 lpar |= DHU_LP_BITS6|DHU_LP_PENABLE; 488 else if (tp->t_flags & (RAW|LITOUT|PASS8)) 489 lpar |= DHU_LP_BITS8; 490 else 491 lpar |= DHU_LP_BITS7|DHU_LP_PENABLE; 492 if (tp->t_flags&EVENP) 493 lpar |= DHU_LP_EPAR; 494 if ((tp->t_ospeed) == B110) 495 lpar |= DHU_LP_TWOSB; 496 addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 497 addr->dhulpr = lpar; 498 splx(s); 499 } 500 501 /* 502 * DHU11 transmitter interrupt. 503 * Restart each line which used to be active but has 504 * terminated transmission since the last interrupt. 505 */ 506 dhuxint(dhu) 507 int dhu; 508 { 509 register struct tty *tp; 510 register struct dhudevice *addr; 511 register struct tty *tp0; 512 register struct uba_device *ui; 513 register int line, t; 514 u_short cntr; 515 516 ui = dhuinfo[dhu]; 517 tp0 = &dhu_tty[dhu<<4]; 518 addr = (struct dhudevice *)ui->ui_addr; 519 while ((t = addr->dhucsrh) & DHU_CSH_TI) { 520 line = DHU_TX_LINE(t); 521 tp = tp0 + line; 522 tp->t_state &= ~TS_BUSY; 523 if (t & DHU_CSH_NXM) { 524 printf("dhu(%d,%d): NXM fault\n", dhu, line); 525 /* SHOULD RESTART OR SOMETHING... */ 526 } 527 if (tp->t_state&TS_FLUSH) 528 tp->t_state &= ~TS_FLUSH; 529 else { 530 addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 531 /* 532 * Do arithmetic in a short to make up 533 * for lost 16&17 bits. 534 */ 535 cntr = addr->dhubar1 - 536 UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 537 ndflush(&tp->t_outq, (int)cntr); 538 } 539 if (tp->t_line) 540 (*linesw[tp->t_line].l_start)(tp); 541 else 542 dhustart(tp); 543 } 544 } 545 546 /* 547 * Start (restart) transmission on the given DHU11 line. 548 */ 549 dhustart(tp) 550 register struct tty *tp; 551 { 552 register struct dhudevice *addr; 553 register int car, dhu, unit, nch; 554 int s; 555 556 unit = minor(tp->t_dev); 557 dhu = unit >> 4; 558 unit &= 0xf; 559 addr = (struct dhudevice *)tp->t_addr; 560 561 /* 562 * Must hold interrupts in following code to prevent 563 * state of the tp from changing. 564 */ 565 s = spl5(); 566 /* 567 * If it's currently active, or delaying, no need to do anything. 568 */ 569 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 570 goto out; 571 /* 572 * If there are sleepers, and output has drained below low 573 * water mark, wake up the sleepers.. 574 */ 575 if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 576 if (tp->t_state&TS_ASLEEP) { 577 tp->t_state &= ~TS_ASLEEP; 578 wakeup((caddr_t)&tp->t_outq); 579 } 580 if (tp->t_wsel) { 581 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 582 tp->t_wsel = 0; 583 tp->t_state &= ~TS_WCOLL; 584 } 585 } 586 /* 587 * Now restart transmission unless the output queue is 588 * empty. 589 */ 590 if (tp->t_outq.c_cc == 0) 591 goto out; 592 if (tp->t_flags & (RAW|LITOUT)) 593 nch = ndqb(&tp->t_outq, 0); 594 else { 595 nch = ndqb(&tp->t_outq, 0200); 596 /* 597 * If first thing on queue is a delay process it. 598 */ 599 if (nch == 0) { 600 nch = getc(&tp->t_outq); 601 timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 602 tp->t_state |= TS_TIMEOUT; 603 goto out; 604 } 605 } 606 /* 607 * If characters to transmit, restart transmission. 608 */ 609 if (nch) { 610 car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 611 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 612 addr->dhulcr &= ~DHU_LC_TXABORT; 613 addr->dhubcr = nch; 614 addr->dhubar1 = car; 615 addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 616 DHU_BA2_DMAGO; 617 tp->t_state |= TS_BUSY; 618 } 619 out: 620 splx(s); 621 } 622 623 /* 624 * Stop output on a line, e.g. for ^S/^Q or output flush. 625 */ 626 /*ARGSUSED*/ 627 dhustop(tp, flag) 628 register struct tty *tp; 629 { 630 register struct dhudevice *addr; 631 register int unit, s; 632 633 addr = (struct dhudevice *)tp->t_addr; 634 /* 635 * Block input/output interrupts while messing with state. 636 */ 637 s = spl5(); 638 if (tp->t_state & TS_BUSY) { 639 /* 640 * Device is transmitting; stop output 641 * by selecting the line and setting the 642 * abort xmit bit. We will get an xmit interrupt, 643 * where we will figure out where to continue the 644 * next time the transmitter is enabled. If 645 * TS_FLUSH is set, the outq will be flushed. 646 * In either case, dhustart will clear the TXABORT bit. 647 */ 648 unit = minor(tp->t_dev); 649 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 650 addr->dhulcr |= DHU_LC_TXABORT; 651 if ((tp->t_state&TS_TTSTOP)==0) 652 tp->t_state |= TS_FLUSH; 653 } 654 (void) splx(s); 655 } 656 657 /* 658 * DHU11 modem control 659 */ 660 dhumctl(dev, bits, how) 661 dev_t dev; 662 int bits, how; 663 { 664 register struct dhudevice *dhuaddr; 665 register int unit, mbits, lcr; 666 int s; 667 668 unit = UNIT(dev); 669 dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 670 unit &= 0xf; 671 s = spl5(); 672 dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 673 /* 674 * combine byte from stat register (read only, bits 16..23) 675 * with lcr register (read write, bits 0..15). 676 */ 677 mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 678 switch (how) { 679 case DMSET: 680 mbits = (mbits & 0xff0000) | bits; 681 break; 682 683 case DMBIS: 684 mbits |= bits; 685 break; 686 687 case DMBIC: 688 mbits &= ~bits; 689 break; 690 691 case DMGET: 692 (void) splx(s); 693 return(mbits); 694 } 695 dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 696 dhuaddr->dhulcr2 = DHU_LC2_TXEN; 697 (void) splx(s); 698 return(mbits); 699 } 700 701 /* 702 * Reset state of driver if UBA reset was necessary. 703 * Reset the line and modem control registers. 704 * restart transmitters. 705 */ 706 dhureset(uban) 707 int uban; 708 { 709 register int dhu, unit; 710 register struct tty *tp; 711 register struct uba_device *ui; 712 register struct dhudevice *addr; 713 int i; 714 register int s; 715 716 for (dhu = 0; dhu < NDHU; dhu++) { 717 ui = dhuinfo[dhu]; 718 if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 719 continue; 720 printf(" dhu%d", dhu); 721 if (dhu_ubinfo[uban]) { 722 dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 723 nclist*sizeof (struct cblock), 0); 724 cbase[uban] = UBAI_ADDR(dhu_ubinfo[uban]); 725 } 726 addr = (struct dhudevice *)ui->ui_addr; 727 addr->dhucsr = DHU_SELECT(0) | DHU_IE; 728 addr->dhutimo = DHU_DEF_TIMO; 729 unit = dhu * 16; 730 for (i = 0; i < 16; i++) { 731 tp = &dhu_tty[unit]; 732 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 733 dhuparam(unit); 734 (void)dhumctl(unit, DHU_ON, DMSET); 735 tp->t_state &= ~TS_BUSY; 736 dhustart(tp); 737 } 738 unit++; 739 } 740 } 741 } 742 #endif 743