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.10 (Berkeley) 04/22/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 #ifdef VAX630 309 (void) spl5(); 310 #endif 311 ui = dhuinfo[dhu]; 312 if (ui == 0 || ui->ui_alive == 0) 313 return; 314 addr = (struct dhudevice *)ui->ui_addr; 315 tp0 = &dhu_tty[dhu<<4]; 316 /* 317 * Loop fetching characters from the silo for this 318 * dhu until there are no more in the silo. 319 */ 320 while ((c = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 321 line = DHU_RX_LINE(c); 322 tp = tp0 + line; 323 if ((c & DHU_RB_STAT) == DHU_RB_STAT) { 324 /* 325 * modem changed or diag info 326 */ 327 if (c & DHU_RB_DIAG) { 328 /* decode diagnostic messages */ 329 continue; 330 } 331 if (c & DHU_ST_DCD) 332 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 333 else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 334 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 335 (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 336 continue; 337 } 338 if ((tp->t_state&TS_ISOPEN) == 0) { 339 wakeup((caddr_t)&tp->t_rawq); 340 #ifdef PORTSELECTOR 341 if ((tp->t_state&TS_WOPEN) == 0) 342 #endif 343 continue; 344 } 345 if (c & DHU_RB_PE) 346 if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 347 (tp->t_flags&(EVENP|ODDP)) == ODDP) 348 continue; 349 if ((c & DHU_RB_DO) && overrun == 0) { 350 log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 351 overrun = 1; 352 } 353 if (c & DHU_RB_FE) 354 /* 355 * At framing error (break) generate 356 * a null (in raw mode, for getty), or a 357 * interrupt (in cooked/cbreak mode). 358 */ 359 if (tp->t_flags&RAW) 360 c = 0; 361 else 362 c = tp->t_intrc; 363 #if NBK > 0 364 if (tp->t_line == NETLDISC) { 365 c &= 0x7f; 366 BKINPUT(c, tp); 367 } else 368 #endif 369 (*linesw[tp->t_line].l_rint)(c, tp); 370 } 371 } 372 373 /* 374 * Ioctl for DHU11. 375 */ 376 /*ARGSUSED*/ 377 dhuioctl(dev, cmd, data, flag) 378 caddr_t data; 379 { 380 register struct tty *tp; 381 register int unit = UNIT(dev); 382 int error; 383 384 tp = &dhu_tty[unit]; 385 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 386 if (error >= 0) 387 return (error); 388 error = ttioctl(tp, cmd, data, flag); 389 if (error >= 0) { 390 if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET || 391 cmd == TIOCLBIC || cmd == TIOCLBIS) 392 dhuparam(unit); 393 return (error); 394 } 395 396 switch (cmd) { 397 case TIOCSBRK: 398 (void) dhumctl(unit, DHU_BRK, DMBIS); 399 break; 400 401 case TIOCCBRK: 402 (void) dhumctl(unit, DHU_BRK, DMBIC); 403 break; 404 405 case TIOCSDTR: 406 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 407 break; 408 409 case TIOCCDTR: 410 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 411 break; 412 413 case TIOCMSET: 414 (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 415 break; 416 417 case TIOCMBIS: 418 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 419 break; 420 421 case TIOCMBIC: 422 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 423 break; 424 425 case TIOCMGET: 426 *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 427 break; 428 default: 429 return (ENOTTY); 430 } 431 return (0); 432 } 433 434 dmtodhu(bits) 435 register int bits; 436 { 437 register int b = 0; 438 439 if (bits & DML_RTS) b |= DHU_RTS; 440 if (bits & DML_DTR) b |= DHU_DTR; 441 if (bits & DML_LE) b |= DHU_LE; 442 return(b); 443 } 444 445 dhutodm(bits) 446 register int bits; 447 { 448 register int b = 0; 449 450 if (bits & DHU_DSR) b |= DML_DSR; 451 if (bits & DHU_RNG) b |= DML_RNG; 452 if (bits & DHU_CAR) b |= DML_CAR; 453 if (bits & DHU_CTS) b |= DML_CTS; 454 if (bits & DHU_RTS) b |= DML_RTS; 455 if (bits & DHU_DTR) b |= DML_DTR; 456 if (bits & DHU_LE) b |= DML_LE; 457 return(b); 458 } 459 460 461 /* 462 * Set parameters from open or stty into the DHU hardware 463 * registers. 464 */ 465 dhuparam(unit) 466 register int unit; 467 { 468 register struct tty *tp; 469 register struct dhudevice *addr; 470 register int lpar; 471 int s; 472 473 tp = &dhu_tty[unit]; 474 addr = (struct dhudevice *)tp->t_addr; 475 /* 476 * Block interrupts so parameters will be set 477 * before the line interrupts. 478 */ 479 s = spl5(); 480 if ((tp->t_ispeed) == 0) { 481 tp->t_state |= TS_HUPCLS; 482 (void)dhumctl(unit, DHU_OFF, DMSET); 483 splx(s); 484 return; 485 } 486 lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8); 487 if ((tp->t_ispeed) == B134) 488 lpar |= DHU_LP_BITS6|DHU_LP_PENABLE; 489 else if (tp->t_flags & (RAW|LITOUT|PASS8)) 490 lpar |= DHU_LP_BITS8; 491 else 492 lpar |= DHU_LP_BITS7|DHU_LP_PENABLE; 493 if (tp->t_flags&EVENP) 494 lpar |= DHU_LP_EPAR; 495 if ((tp->t_ospeed) == B110) 496 lpar |= DHU_LP_TWOSB; 497 addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 498 addr->dhulpr = lpar; 499 splx(s); 500 } 501 502 /* 503 * DHU11 transmitter interrupt. 504 * Restart each line which used to be active but has 505 * terminated transmission since the last interrupt. 506 */ 507 dhuxint(dhu) 508 int dhu; 509 { 510 register struct tty *tp; 511 register struct dhudevice *addr; 512 register struct tty *tp0; 513 register struct uba_device *ui; 514 register int line, t; 515 u_short cntr; 516 517 #ifdef VAX630 518 (void) spl5(); 519 #endif 520 ui = dhuinfo[dhu]; 521 tp0 = &dhu_tty[dhu<<4]; 522 addr = (struct dhudevice *)ui->ui_addr; 523 while ((t = addr->dhucsrh) & DHU_CSH_TI) { 524 line = DHU_TX_LINE(t); 525 tp = tp0 + line; 526 tp->t_state &= ~TS_BUSY; 527 if (t & DHU_CSH_NXM) { 528 printf("dhu(%d,%d): NXM fault\n", dhu, line); 529 /* SHOULD RESTART OR SOMETHING... */ 530 } 531 if (tp->t_state&TS_FLUSH) 532 tp->t_state &= ~TS_FLUSH; 533 else { 534 addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 535 /* 536 * Do arithmetic in a short to make up 537 * for lost 16&17 bits. 538 */ 539 cntr = addr->dhubar1 - 540 UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 541 ndflush(&tp->t_outq, (int)cntr); 542 } 543 if (tp->t_line) 544 (*linesw[tp->t_line].l_start)(tp); 545 else 546 dhustart(tp); 547 } 548 } 549 550 /* 551 * Start (restart) transmission on the given DHU11 line. 552 */ 553 dhustart(tp) 554 register struct tty *tp; 555 { 556 register struct dhudevice *addr; 557 register int car, dhu, unit, nch; 558 int s; 559 560 unit = minor(tp->t_dev); 561 dhu = unit >> 4; 562 unit &= 0xf; 563 addr = (struct dhudevice *)tp->t_addr; 564 565 /* 566 * Must hold interrupts in following code to prevent 567 * state of the tp from changing. 568 */ 569 s = spl5(); 570 /* 571 * If it's currently active, or delaying, no need to do anything. 572 */ 573 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 574 goto out; 575 /* 576 * If there are sleepers, and output has drained below low 577 * water mark, wake up the sleepers.. 578 */ 579 if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 580 if (tp->t_state&TS_ASLEEP) { 581 tp->t_state &= ~TS_ASLEEP; 582 wakeup((caddr_t)&tp->t_outq); 583 } 584 if (tp->t_wsel) { 585 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 586 tp->t_wsel = 0; 587 tp->t_state &= ~TS_WCOLL; 588 } 589 } 590 /* 591 * Now restart transmission unless the output queue is 592 * empty. 593 */ 594 if (tp->t_outq.c_cc == 0) 595 goto out; 596 if (tp->t_flags & (RAW|LITOUT)) 597 nch = ndqb(&tp->t_outq, 0); 598 else { 599 nch = ndqb(&tp->t_outq, 0200); 600 /* 601 * If first thing on queue is a delay process it. 602 */ 603 if (nch == 0) { 604 nch = getc(&tp->t_outq); 605 timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 606 tp->t_state |= TS_TIMEOUT; 607 goto out; 608 } 609 } 610 /* 611 * If characters to transmit, restart transmission. 612 */ 613 if (nch) { 614 car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 615 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 616 addr->dhulcr &= ~DHU_LC_TXABORT; 617 addr->dhubcr = nch; 618 addr->dhubar1 = car; 619 addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 620 DHU_BA2_DMAGO; 621 tp->t_state |= TS_BUSY; 622 } 623 out: 624 splx(s); 625 } 626 627 /* 628 * Stop output on a line, e.g. for ^S/^Q or output flush. 629 */ 630 /*ARGSUSED*/ 631 dhustop(tp, flag) 632 register struct tty *tp; 633 { 634 register struct dhudevice *addr; 635 register int unit, s; 636 637 addr = (struct dhudevice *)tp->t_addr; 638 /* 639 * Block input/output interrupts while messing with state. 640 */ 641 s = spl5(); 642 if (tp->t_state & TS_BUSY) { 643 /* 644 * Device is transmitting; stop output 645 * by selecting the line and setting the 646 * abort xmit bit. We will get an xmit interrupt, 647 * where we will figure out where to continue the 648 * next time the transmitter is enabled. If 649 * TS_FLUSH is set, the outq will be flushed. 650 * In either case, dhustart will clear the TXABORT bit. 651 */ 652 unit = minor(tp->t_dev); 653 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 654 addr->dhulcr |= DHU_LC_TXABORT; 655 if ((tp->t_state&TS_TTSTOP)==0) 656 tp->t_state |= TS_FLUSH; 657 } 658 (void) splx(s); 659 } 660 661 /* 662 * DHU11 modem control 663 */ 664 dhumctl(dev, bits, how) 665 dev_t dev; 666 int bits, how; 667 { 668 register struct dhudevice *dhuaddr; 669 register int unit, mbits; 670 int s; 671 672 unit = UNIT(dev); 673 dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 674 unit &= 0xf; 675 s = spl5(); 676 dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 677 /* 678 * combine byte from stat register (read only, bits 16..23) 679 * with lcr register (read write, bits 0..15). 680 */ 681 mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 682 switch (how) { 683 case DMSET: 684 mbits = (mbits & 0xff0000) | bits; 685 break; 686 687 case DMBIS: 688 mbits |= bits; 689 break; 690 691 case DMBIC: 692 mbits &= ~bits; 693 break; 694 695 case DMGET: 696 (void) splx(s); 697 return(mbits); 698 } 699 dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 700 dhuaddr->dhulcr2 = DHU_LC2_TXEN; 701 (void) splx(s); 702 return(mbits); 703 } 704 705 /* 706 * Reset state of driver if UBA reset was necessary. 707 * Reset the line and modem control registers. 708 * restart transmitters. 709 */ 710 dhureset(uban) 711 int uban; 712 { 713 register int dhu, unit; 714 register struct tty *tp; 715 register struct uba_device *ui; 716 register struct dhudevice *addr; 717 int i; 718 719 for (dhu = 0; dhu < NDHU; dhu++) { 720 ui = dhuinfo[dhu]; 721 if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 722 continue; 723 printf(" dhu%d", dhu); 724 if (dhu_ubinfo[uban]) { 725 dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 726 nclist*sizeof (struct cblock), 0); 727 cbase[uban] = UBAI_ADDR(dhu_ubinfo[uban]); 728 } 729 addr = (struct dhudevice *)ui->ui_addr; 730 addr->dhucsr = DHU_SELECT(0) | DHU_IE; 731 addr->dhutimo = DHU_DEF_TIMO; 732 unit = dhu * 16; 733 for (i = 0; i < 16; i++) { 734 tp = &dhu_tty[unit]; 735 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 736 dhuparam(unit); 737 (void)dhumctl(unit, DHU_ON, DMSET); 738 tp->t_state &= ~TS_BUSY; 739 dhustart(tp); 740 } 741 unit++; 742 } 743 } 744 } 745 #endif 746