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