1 /* 2 * Copyright (c) 1982 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.6 (Berkeley) 11/08/85 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 }; /* 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 } 166 167 /* 168 * Open a DHU11 line, mapping the clist onto the uba if this 169 * is the first dhu on this uba. Turn on this dhu if this is 170 * the first use of it. 171 */ 172 /*ARGSUSED*/ 173 dhuopen(dev, flag) 174 dev_t dev; 175 { 176 register struct tty *tp; 177 register int unit, dhu; 178 register struct dhudevice *addr; 179 register struct uba_device *ui; 180 int s; 181 182 unit = UNIT(dev); 183 dhu = unit >> 4; 184 if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0) 185 return (ENXIO); 186 tp = &dhu_tty[unit]; 187 if (tp->t_state & TS_XCLUDE && u.u_uid != 0) 188 return (EBUSY); 189 addr = (struct dhudevice *)ui->ui_addr; 190 tp->t_addr = (caddr_t)addr; 191 tp->t_oproc = dhustart; 192 /* 193 * While setting up state for this uba and this dhu, 194 * block uba resets which can clear the state. 195 */ 196 s = spl5(); 197 if (cbase[ui->ui_ubanum] == 0) { 198 dhu_ubinfo[ui->ui_ubanum] = 199 uballoc(ui->ui_ubanum, (caddr_t)cfree, 200 nclist*sizeof(struct cblock), 0); 201 cbase[ui->ui_ubanum] = dhu_ubinfo[ui->ui_ubanum]&0x3ffff; 202 } 203 if ((dhuact&(1<<dhu)) == 0) { 204 addr->dhucsr = DHU_SELECT(0) | DHU_IE; 205 addr->dhutimo = DHU_DEF_TIMO; 206 dhuact |= (1<<dhu); 207 /* anything else to configure whole board */ 208 } 209 (void) splx(s); 210 /* 211 * If this is first open, initialize tty state to default. 212 */ 213 if ((tp->t_state&TS_ISOPEN) == 0) { 214 ttychars(tp); 215 #ifndef PORTSELECTOR 216 if (tp->t_ispeed == 0) { 217 #else 218 tp->t_state |= TS_HUPCLS; 219 #endif PORTSELECTOR 220 tp->t_ispeed = ISPEED; 221 tp->t_ospeed = ISPEED; 222 tp->t_flags = IFLAGS; 223 #ifndef PORTSELECTOR 224 } 225 #endif PORTSELECTOR 226 tp->t_dev = dev; 227 dhuparam(unit); 228 } 229 /* 230 * Wait for carrier, then process line discipline specific open. 231 */ 232 s = spl5(); 233 if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) || 234 (dhusoftCAR[dhu] & (1<<(unit&0xf)))) 235 tp->t_state |= TS_CARR_ON; 236 while ((tp->t_state & TS_CARR_ON) == 0) { 237 tp->t_state |= TS_WOPEN; 238 sleep((caddr_t)&tp->t_rawq, TTIPRI); 239 } 240 (void) splx(s); 241 return ((*linesw[tp->t_line].l_open)(dev, tp)); 242 } 243 244 /* 245 * Close a DHU11 line, turning off the modem control. 246 */ 247 /*ARGSUSED*/ 248 dhuclose(dev, flag) 249 dev_t dev; 250 int flag; 251 { 252 register struct tty *tp; 253 register unit; 254 255 unit = UNIT(dev); 256 tp = &dhu_tty[unit]; 257 (*linesw[tp->t_line].l_close)(tp); 258 (void) dhumctl(unit, DHU_BRK, DMBIC); 259 if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0) 260 #ifdef PORTSELECTOR 261 { 262 extern int wakeup(); 263 264 (void) dhumctl(unit, DHU_OFF, DMSET); 265 /* Hold DTR low for 0.5 seconds */ 266 timeout(wakeup, (caddr_t) &tp->t_dev, hz/2); 267 sleep((caddr_t) &tp->t_dev, PZERO); 268 } 269 #else 270 (void) dhumctl(unit, DHU_OFF, DMSET); 271 #endif PORTSELECTOR 272 ttyclose(tp); 273 } 274 275 dhuread(dev, uio) 276 dev_t dev; 277 struct uio *uio; 278 { 279 register struct tty *tp = &dhu_tty[UNIT(dev)]; 280 281 return ((*linesw[tp->t_line].l_read)(tp, uio)); 282 } 283 284 dhuwrite(dev, uio) 285 dev_t dev; 286 struct uio *uio; 287 { 288 register struct tty *tp = &dhu_tty[UNIT(dev)]; 289 290 return ((*linesw[tp->t_line].l_write)(tp, uio)); 291 } 292 293 /* 294 * DHU11 receiver interrupt. 295 */ 296 dhurint(dhu) 297 int dhu; 298 { 299 register struct tty *tp; 300 register c; 301 register struct dhudevice *addr; 302 register struct tty *tp0; 303 register struct uba_device *ui; 304 register line; 305 int overrun = 0; 306 307 ui = dhuinfo[dhu]; 308 if (ui == 0 || ui->ui_alive == 0) 309 return; 310 addr = (struct dhudevice *)ui->ui_addr; 311 tp0 = &dhu_tty[dhu<<4]; 312 /* 313 * Loop fetching characters from the silo for this 314 * dhu until there are no more in the silo. 315 */ 316 while ((c = addr->dhurbuf) < 0) { /* (c & DHU_RB_VALID) == on */ 317 line = DHU_RX_LINE(c); 318 tp = tp0 + line; 319 if ((c & DHU_RB_STAT) == DHU_RB_STAT) { 320 /* 321 * modem changed or diag info 322 */ 323 if (c & DHU_RB_DIAG) { 324 /* decode diagnostic messages */ 325 continue; 326 } 327 if (c & DHU_ST_DCD) 328 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 329 else if ((dhusoftCAR[dhu] & (1<<line)) == 0 && 330 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) 331 (void) dhumctl((dhu<<4)|line, DHU_OFF, DMSET); 332 continue; 333 } 334 if ((tp->t_state&TS_ISOPEN) == 0) { 335 wakeup((caddr_t)&tp->t_rawq); 336 #ifdef PORTSELECTOR 337 if ((tp->t_state&TS_WOPEN) == 0) 338 #endif 339 continue; 340 } 341 if (c & DHU_RB_PE) 342 if ((tp->t_flags&(EVENP|ODDP)) == EVENP || 343 (tp->t_flags&(EVENP|ODDP)) == ODDP) 344 continue; 345 if ((c & DHU_RB_DO) && overrun == 0) { 346 log(LOG_WARNING, "dhu%d: silo overflow\n", dhu); 347 overrun = 1; 348 } 349 if (c & DHU_RB_FE) 350 /* 351 * At framing error (break) generate 352 * a null (in raw mode, for getty), or a 353 * interrupt (in cooked/cbreak mode). 354 */ 355 if (tp->t_flags&RAW) 356 c = 0; 357 else 358 c = tp->t_intrc; 359 #if NBK > 0 360 if (tp->t_line == NETLDISC) { 361 c &= 0x7f; 362 BKINPUT(c, tp); 363 } else 364 #endif 365 (*linesw[tp->t_line].l_rint)(c, tp); 366 } 367 } 368 369 /* 370 * Ioctl for DHU11. 371 */ 372 /*ARGSUSED*/ 373 dhuioctl(dev, cmd, data, flag) 374 caddr_t data; 375 { 376 register struct tty *tp; 377 register int unit = UNIT(dev); 378 register dhu = unit>>4; 379 register bit = (1<<(unit&0xf)); 380 int error; 381 382 tp = &dhu_tty[unit]; 383 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 384 if (error >= 0) 385 return (error); 386 error = ttioctl(tp, cmd, data, flag); 387 if (error >= 0) { 388 if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET || 389 cmd == TIOCLBIC || cmd == TIOCLBIS) 390 dhuparam(unit); 391 return (error); 392 } 393 394 switch (cmd) { 395 case TIOCSBRK: 396 (void) dhumctl(unit, DHU_BRK, DMBIS); 397 break; 398 399 case TIOCCBRK: 400 (void) dhumctl(unit, DHU_BRK, DMBIC); 401 break; 402 403 case TIOCSDTR: 404 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS); 405 break; 406 407 case TIOCCDTR: 408 (void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC); 409 break; 410 411 case TIOCMSET: 412 (void) dhumctl(dev, dmtodhu(*(int *)data), DMSET); 413 break; 414 415 case TIOCMBIS: 416 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS); 417 break; 418 419 case TIOCMBIC: 420 (void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC); 421 break; 422 423 case TIOCMGET: 424 *(int *)data = dhutodm(dhumctl(dev, 0, DMGET)); 425 break; 426 default: 427 return (ENOTTY); 428 } 429 return (0); 430 } 431 432 dmtodhu(bits) 433 register int bits; 434 { 435 register int b = 0; 436 437 if (bits & DML_RTS) b |= DHU_RTS; 438 if (bits & DML_DTR) b |= DHU_DTR; 439 if (bits & DML_LE) b |= DHU_LE; 440 return(b); 441 } 442 443 dhutodm(bits) 444 register int bits; 445 { 446 register int b = 0; 447 448 if (bits & DHU_DSR) b |= DML_DSR; 449 if (bits & DHU_RNG) b |= DML_RNG; 450 if (bits & DHU_CAR) b |= DML_CAR; 451 if (bits & DHU_CTS) b |= DML_CTS; 452 if (bits & DHU_RTS) b |= DML_RTS; 453 if (bits & DHU_DTR) b |= DML_DTR; 454 if (bits & DHU_LE) b |= DML_LE; 455 return(b); 456 } 457 458 459 /* 460 * Set parameters from open or stty into the DHU hardware 461 * registers. 462 */ 463 dhuparam(unit) 464 register int unit; 465 { 466 register struct tty *tp; 467 register struct dhudevice *addr; 468 register int lpar; 469 int s; 470 471 tp = &dhu_tty[unit]; 472 addr = (struct dhudevice *)tp->t_addr; 473 /* 474 * Block interrupts so parameters will be set 475 * before the line interrupts. 476 */ 477 s = spl5(); 478 if ((tp->t_ispeed) == 0) { 479 tp->t_state |= TS_HUPCLS; 480 (void)dhumctl(unit, DHU_OFF, DMSET); 481 splx(s); 482 return; 483 } 484 lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8); 485 if ((tp->t_ispeed) == B134) 486 lpar |= DHU_LP_BITS6|DHU_LP_PENABLE; 487 else if (tp->t_flags & (RAW|LITOUT|PASS8)) 488 lpar |= DHU_LP_BITS8; 489 else 490 lpar |= DHU_LP_BITS7|DHU_LP_PENABLE; 491 if (tp->t_flags&EVENP) 492 lpar |= DHU_LP_EPAR; 493 if ((tp->t_ospeed) == B110) 494 lpar |= DHU_LP_TWOSB; 495 addr->dhucsr = DHU_SELECT(unit) | DHU_IE; 496 addr->dhulpr = lpar; 497 splx(s); 498 } 499 500 /* 501 * DHU11 transmitter interrupt. 502 * Restart each line which used to be active but has 503 * terminated transmission since the last interrupt. 504 */ 505 dhuxint(dhu) 506 int dhu; 507 { 508 register struct tty *tp; 509 register struct dhudevice *addr; 510 register struct tty *tp0; 511 register struct uba_device *ui; 512 register int line, t; 513 u_short cntr; 514 515 ui = dhuinfo[dhu]; 516 tp0 = &dhu_tty[dhu<<4]; 517 addr = (struct dhudevice *)ui->ui_addr; 518 while ((t = addr->dhucsrh) & DHU_CSH_TI) { 519 line = DHU_TX_LINE(t); 520 tp = tp0 + line; 521 tp->t_state &= ~TS_BUSY; 522 if (t & DHU_CSH_NXM) { 523 printf("dhu(%d,%d): NXM fault\n", dhu, line); 524 /* SHOULD RESTART OR SOMETHING... */ 525 } 526 if (tp->t_state&TS_FLUSH) 527 tp->t_state &= ~TS_FLUSH; 528 else { 529 addr->dhucsrl = DHU_SELECT(line) | DHU_IE; 530 /* 531 * Do arithmetic in a short to make up 532 * for lost 16&17 bits. 533 */ 534 cntr = addr->dhubar1 - 535 UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); 536 ndflush(&tp->t_outq, (int)cntr); 537 } 538 if (tp->t_line) 539 (*linesw[tp->t_line].l_start)(tp); 540 else 541 dhustart(tp); 542 } 543 } 544 545 /* 546 * Start (restart) transmission on the given DHU11 line. 547 */ 548 dhustart(tp) 549 register struct tty *tp; 550 { 551 register struct dhudevice *addr; 552 register int car, dhu, unit, nch; 553 int s; 554 555 unit = minor(tp->t_dev); 556 dhu = unit >> 4; 557 unit &= 0xf; 558 addr = (struct dhudevice *)tp->t_addr; 559 560 /* 561 * Must hold interrupts in following code to prevent 562 * state of the tp from changing. 563 */ 564 s = spl5(); 565 /* 566 * If it's currently active, or delaying, no need to do anything. 567 */ 568 if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 569 goto out; 570 /* 571 * If there are sleepers, and output has drained below low 572 * water mark, wake up the sleepers.. 573 */ 574 if (tp->t_outq.c_cc<=TTLOWAT(tp)) { 575 if (tp->t_state&TS_ASLEEP) { 576 tp->t_state &= ~TS_ASLEEP; 577 wakeup((caddr_t)&tp->t_outq); 578 } 579 if (tp->t_wsel) { 580 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 581 tp->t_wsel = 0; 582 tp->t_state &= ~TS_WCOLL; 583 } 584 } 585 /* 586 * Now restart transmission unless the output queue is 587 * empty. 588 */ 589 if (tp->t_outq.c_cc == 0) 590 goto out; 591 if (tp->t_flags & (RAW|LITOUT)) 592 nch = ndqb(&tp->t_outq, 0); 593 else { 594 nch = ndqb(&tp->t_outq, 0200); 595 /* 596 * If first thing on queue is a delay process it. 597 */ 598 if (nch == 0) { 599 nch = getc(&tp->t_outq); 600 timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); 601 tp->t_state |= TS_TIMEOUT; 602 goto out; 603 } 604 } 605 /* 606 * If characters to transmit, restart transmission. 607 */ 608 if (nch) { 609 car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum); 610 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 611 addr->dhulcr &= ~DHU_LC_TXABORT; 612 addr->dhubcr = nch; 613 addr->dhubar1 = car; 614 addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) | 615 DHU_BA2_DMAGO; 616 tp->t_state |= TS_BUSY; 617 } 618 out: 619 splx(s); 620 } 621 622 /* 623 * Stop output on a line, e.g. for ^S/^Q or output flush. 624 */ 625 /*ARGSUSED*/ 626 dhustop(tp, flag) 627 register struct tty *tp; 628 { 629 register struct dhudevice *addr; 630 register int unit, s; 631 632 addr = (struct dhudevice *)tp->t_addr; 633 /* 634 * Block input/output interrupts while messing with state. 635 */ 636 s = spl5(); 637 if (tp->t_state & TS_BUSY) { 638 /* 639 * Device is transmitting; stop output 640 * by selecting the line and setting the 641 * abort xmit bit. We will get an xmit interrupt, 642 * where we will figure out where to continue the 643 * next time the transmitter is enabled. If 644 * TS_FLUSH is set, the outq will be flushed. 645 * In either case, dhustart will clear the TXABORT bit. 646 */ 647 unit = minor(tp->t_dev); 648 addr->dhucsrl = DHU_SELECT(unit) | DHU_IE; 649 addr->dhulcr |= DHU_LC_TXABORT; 650 if ((tp->t_state&TS_TTSTOP)==0) 651 tp->t_state |= TS_FLUSH; 652 } 653 (void) splx(s); 654 } 655 656 /* 657 * DHU11 modem control 658 */ 659 dhumctl(dev, bits, how) 660 dev_t dev; 661 int bits, how; 662 { 663 register struct dhudevice *dhuaddr; 664 register int unit, mbits, lcr; 665 int s; 666 667 unit = UNIT(dev); 668 dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr); 669 unit &= 0xf; 670 s = spl5(); 671 dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE; 672 /* 673 * combine byte from stat register (read only, bits 16..23) 674 * with lcr register (read write, bits 0..15). 675 */ 676 mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16); 677 switch (how) { 678 case DMSET: 679 mbits = (mbits & 0xff0000) | bits; 680 break; 681 682 case DMBIS: 683 mbits |= bits; 684 break; 685 686 case DMBIC: 687 mbits &= ~bits; 688 break; 689 690 case DMGET: 691 (void) splx(s); 692 return(mbits); 693 } 694 dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN; 695 dhuaddr->dhulcr2 = DHU_LC2_TXEN; 696 (void) splx(s); 697 return(mbits); 698 } 699 700 /* 701 * Reset state of driver if UBA reset was necessary. 702 * Reset the line and modem control registers. 703 * restart transmitters. 704 */ 705 dhureset(uban) 706 int uban; 707 { 708 register int dhu, unit; 709 register struct tty *tp; 710 register struct uba_device *ui; 711 register struct dhudevice *addr; 712 int i; 713 register int s; 714 715 for (dhu = 0; dhu < NDHU; dhu++) { 716 ui = dhuinfo[dhu]; 717 if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 718 continue; 719 printf(" dhu%d", dhu); 720 if (cbase[uban] == 0) { 721 dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree, 722 nclist*sizeof (struct cblock), 0); 723 cbase[uban] = dhu_ubinfo[uban]&0x3ffff; 724 } 725 addr = (struct dhudevice *)ui->ui_addr; 726 addr->dhucsr = DHU_SELECT(0) | DHU_IE; 727 addr->dhutimo = DHU_DEF_TIMO; 728 unit = dhu * 16; 729 for (i = 0; i < 16; i++) { 730 tp = &dhu_tty[unit]; 731 if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { 732 dhuparam(unit); 733 (void)dhumctl(unit, DHU_ON, DMSET); 734 tp->t_state &= ~TS_BUSY; 735 dhustart(tp); 736 } 737 unit++; 738 } 739 } 740 } 741 #endif 742