1 /* $NetBSD: dcm.c,v 1.15 1994/10/26 07:23:34 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1986, 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from Utah: $Hdr: dcm.c 1.29 92/01/21$ 41 * 42 * @(#)dcm.c 8.4 (Berkeley) 1/12/94 43 */ 44 45 /* 46 * TODO: 47 * Timeouts 48 * Test console support. 49 */ 50 51 #include "dcm.h" 52 #if NDCM > 0 53 /* 54 * 98642/MUX 55 */ 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/ioctl.h> 59 #include <sys/proc.h> 60 #include <sys/tty.h> 61 #include <sys/conf.h> 62 #include <sys/file.h> 63 #include <sys/uio.h> 64 #include <sys/kernel.h> 65 #include <sys/syslog.h> 66 #include <sys/time.h> 67 68 #include <machine/cpu.h> 69 70 #include <hp300/dev/device.h> 71 #include <hp300/dev/dcmreg.h> 72 #include <hp300/hp300/isr.h> 73 74 #ifndef DEFAULT_BAUD_RATE 75 #define DEFAULT_BAUD_RATE 9600 76 #endif 77 78 int dcmprobe(), dcmintr(), dcmparam(); 79 void dcmstart(); 80 struct driver dcmdriver = { 81 dcmprobe, "dcm", 82 }; 83 84 #define NDCMLINE (NDCM*4) 85 86 struct tty *dcm_tty[NDCMLINE]; 87 struct modemreg *dcm_modem[NDCMLINE]; 88 char mcndlast[NDCMLINE]; /* XXX last modem status for line */ 89 int ndcm = NDCMLINE; 90 91 int dcm_active; 92 int dcmsoftCAR[NDCM]; 93 struct dcmdevice *dcm_addr[NDCM]; 94 struct isr dcmisr[NDCM]; 95 96 struct speedtab dcmspeedtab[] = { 97 0, BR_0, 98 50, BR_50, 99 75, BR_75, 100 110, BR_110, 101 134, BR_134, 102 150, BR_150, 103 300, BR_300, 104 600, BR_600, 105 1200, BR_1200, 106 1800, BR_1800, 107 2400, BR_2400, 108 4800, BR_4800, 109 9600, BR_9600, 110 19200, BR_19200, 111 38400, BR_38400, 112 -1, -1 113 }; 114 115 /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */ 116 #define DCM_USPERCH(s) (10000000 / (s)) 117 118 /* 119 * Per board interrupt scheme. 16.7ms is the polling interrupt rate 120 * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms). 121 */ 122 #define DIS_TIMER 0 123 #define DIS_PERCHAR 1 124 #define DIS_RESET 2 125 126 int dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */ 127 int dcminterval = 5; /* interval (secs) between checks */ 128 struct dcmischeme { 129 int dis_perchar; /* non-zero if interrupting per char */ 130 long dis_time; /* last time examined */ 131 int dis_intr; /* recv interrupts during last interval */ 132 int dis_char; /* characters read during last interval */ 133 } dcmischeme[NDCM]; 134 135 /* 136 * Console support 137 */ 138 #ifdef DCMCONSOLE 139 int dcmconsole = DCMCONSOLE; 140 #else 141 int dcmconsole = -1; 142 #endif 143 int dcmconsinit; 144 int dcmdefaultrate = DEFAULT_BAUD_RATE; 145 int dcmconbrdbusy = 0; 146 int dcmmajor; 147 148 #ifdef KGDB 149 /* 150 * Kernel GDB support 151 */ 152 #include <machine/remote-sl.h> 153 154 extern dev_t kgdb_dev; 155 extern int kgdb_rate; 156 extern int kgdb_debug_init; 157 #endif 158 159 /* #define DCMSTATS */ 160 161 #ifdef DEBUG 162 int dcmdebug = 0x0; 163 #define DDB_SIOERR 0x01 164 #define DDB_PARAM 0x02 165 #define DDB_INPUT 0x04 166 #define DDB_OUTPUT 0x08 167 #define DDB_INTR 0x10 168 #define DDB_IOCTL 0x20 169 #define DDB_INTSCHM 0x40 170 #define DDB_MODEM 0x80 171 #define DDB_OPENCLOSE 0x100 172 #endif 173 174 #ifdef DCMSTATS 175 #define DCMRBSIZE 94 176 #define DCMXBSIZE 24 177 178 struct dcmstats { 179 long xints; /* # of xmit ints */ 180 long xchars; /* # of xmit chars */ 181 long xempty; /* times outq is empty in dcmstart */ 182 long xrestarts; /* times completed while xmitting */ 183 long rints; /* # of recv ints */ 184 long rchars; /* # of recv chars */ 185 long xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */ 186 long rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */ 187 } dcmstats[NDCM]; 188 #endif 189 190 #define UNIT(x) minor(x) 191 #define BOARD(x) (((x) >> 2) & 0x3f) 192 #define PORT(x) ((x) & 3) 193 #define MKUNIT(b,p) (((b) << 2) | (p)) 194 195 /* 196 * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux, 197 * the distribution panel uses "HP DCE" conventions. If requested via 198 * the device flags, we swap the inputs to something closer to normal DCE, 199 * allowing a straight-through cable to a DTE or a reversed cable 200 * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected; 201 * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect 202 * DSR or make RTS work, though). The following gives the full 203 * details of a cable from this mux panel to a modem: 204 * 205 * HP modem 206 * name pin pin name 207 * HP inputs: 208 * "Rx" 2 3 Tx 209 * CTS 4 5 CTS (only needed for CCTS_OFLOW) 210 * DCD 20 8 DCD 211 * "DSR" 9 6 DSR (unneeded) 212 * RI 22 22 RI (unneeded) 213 * 214 * HP outputs: 215 * "Tx" 3 2 Rx 216 * "DTR" 6 not connected 217 * "RTS" 8 20 DTR 218 * "SR" 23 4 RTS (often not needed) 219 */ 220 #define FLAG_STDDCE 0x10 /* map inputs if this bit is set in flags */ 221 #define hp2dce_in(ibits) (iconv[(ibits) & 0xf]) 222 static char iconv[16] = { 223 0, MI_DM, MI_CTS, MI_CTS|MI_DM, 224 MI_CD, MI_CD|MI_DM, MI_CD|MI_CTS, MI_CD|MI_CTS|MI_DM, 225 MI_RI, MI_RI|MI_DM, MI_RI|MI_CTS, MI_RI|MI_CTS|MI_DM, 226 MI_RI|MI_CD, MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS, 227 MI_RI|MI_CD|MI_CTS|MI_DM 228 }; 229 230 dcmprobe(hd) 231 register struct hp_device *hd; 232 { 233 register struct dcmdevice *dcm; 234 register int i; 235 register int timo = 0; 236 int s, brd, isconsole, mbits; 237 238 dcm = (struct dcmdevice *)hd->hp_addr; 239 if ((dcm->dcm_rsid & 0x1f) != DCMID) 240 return (0); 241 brd = hd->hp_unit; 242 isconsole = (brd == BOARD(dcmconsole)); 243 /* 244 * XXX selected console device (CONSUNIT) as determined by 245 * dcmcnprobe does not agree with logical numbering imposed 246 * by the config file (i.e. lowest address DCM is not unit 247 * CONSUNIT). Don't recognize this card. 248 */ 249 if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)]) 250 return (0); 251 252 /* 253 * Empirically derived self-test magic 254 */ 255 s = spltty(); 256 dcm->dcm_rsid = DCMRS; 257 DELAY(50000); /* 5000 is not long enough */ 258 dcm->dcm_rsid = 0; 259 dcm->dcm_ic = IC_IE; 260 dcm->dcm_cr = CR_SELFT; 261 while ((dcm->dcm_ic & IC_IR) == 0) 262 if (++timo == 20000) 263 return (0); 264 DELAY(50000) /* XXX why is this needed ???? */ 265 while ((dcm->dcm_iir & IIR_SELFT) == 0) 266 if (++timo == 400000) 267 return (0); 268 DELAY(50000) /* XXX why is this needed ???? */ 269 if (dcm->dcm_stcon != ST_OK) { 270 if (!isconsole) 271 printf("dcm%d: self test failed: %x\n", 272 brd, dcm->dcm_stcon); 273 return (0); 274 } 275 dcm->dcm_ic = IC_ID; 276 splx(s); 277 278 hd->hp_ipl = DCMIPL(dcm->dcm_ic); 279 dcm_addr[brd] = dcm; 280 dcm_active |= 1 << brd; 281 dcmsoftCAR[brd] = hd->hp_flags; 282 dcmisr[brd].isr_ipl = hd->hp_ipl; 283 dcmisr[brd].isr_arg = brd; 284 dcmisr[brd].isr_intr = dcmintr; 285 isrlink(&dcmisr[brd]); 286 #ifdef KGDB 287 if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) { 288 if (dcmconsole == UNIT(kgdb_dev)) 289 kgdb_dev = NODEV; /* can't debug over console port */ 290 #ifndef KGDB_CHEAT 291 /* 292 * The following could potentially be replaced 293 * by the corresponding code in dcmcnprobe. 294 */ 295 else { 296 (void) dcminit(kgdb_dev, kgdb_rate); 297 if (kgdb_debug_init) { 298 printf("dcm%d: ", UNIT(kgdb_dev)); 299 kgdb_connect(1); 300 } else 301 printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev)); 302 } 303 /* end could be replaced */ 304 #endif 305 } 306 #endif 307 if (dcmistype == DIS_TIMER) 308 dcmsetischeme(brd, DIS_RESET|DIS_TIMER); 309 else 310 dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR); 311 312 /* load pointers to modem control */ 313 dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0; 314 dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1; 315 dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2; 316 dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3; 317 /* set DCD (modem) and CTS (flow control) on all ports */ 318 if (dcmsoftCAR[brd] & FLAG_STDDCE) 319 mbits = hp2dce_in(MI_CD|MI_CTS); 320 else 321 mbits = MI_CD|MI_CTS; 322 for (i = 0; i < 4; i++) 323 dcm_modem[MKUNIT(brd, i)]->mdmmsk = mbits; 324 325 dcm->dcm_ic = IC_IE; /* turn all interrupts on */ 326 /* 327 * Need to reset baud rate, etc. of next print so reset dcmconsole. 328 * Also make sure console is always "hardwired" 329 */ 330 if (isconsole) { 331 dcmconsinit = 0; 332 dcmsoftCAR[brd] |= (1 << PORT(dcmconsole)); 333 } 334 return (1); 335 } 336 337 /* ARGSUSED */ 338 #ifdef __STDC__ 339 dcmopen(dev_t dev, int flag, int mode, struct proc *p) 340 #else 341 dcmopen(dev, flag, mode, p) 342 dev_t dev; 343 int flag, mode; 344 struct proc *p; 345 #endif 346 { 347 register struct tty *tp; 348 register int unit, brd; 349 int error = 0, mbits; 350 351 unit = UNIT(dev); 352 brd = BOARD(unit); 353 if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0) 354 return (ENXIO); 355 if (!dcm_tty[unit]) 356 tp = dcm_tty[unit] = ttymalloc(); 357 else 358 tp = dcm_tty[unit]; 359 tp->t_oproc = dcmstart; 360 tp->t_param = dcmparam; 361 tp->t_dev = dev; 362 if ((tp->t_state & TS_ISOPEN) == 0) { 363 tp->t_state |= TS_WOPEN; 364 ttychars(tp); 365 if (tp->t_ispeed == 0) { 366 tp->t_iflag = TTYDEF_IFLAG; 367 tp->t_oflag = TTYDEF_OFLAG; 368 tp->t_cflag = TTYDEF_CFLAG; 369 tp->t_lflag = TTYDEF_LFLAG; 370 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 371 } 372 (void) dcmparam(tp, &tp->t_termios); 373 ttsetwater(tp); 374 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 375 return (EBUSY); 376 mbits = MO_ON; 377 if (dcmsoftCAR[brd] & FLAG_STDDCE) 378 mbits |= MO_SR; /* pin 23, could be used as RTS */ 379 (void) dcmmctl(dev, mbits, DMSET); /* enable port */ 380 if ((dcmsoftCAR[brd] & (1 << PORT(unit))) || 381 (dcmmctl(dev, MO_OFF, DMGET) & MI_CD)) 382 tp->t_state |= TS_CARR_ON; 383 #ifdef DEBUG 384 if (dcmdebug & DDB_MODEM) 385 printf("dcm%d: dcmopen port %d softcarr %c\n", 386 brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0'); 387 #endif 388 (void) spltty(); 389 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 390 (tp->t_state & TS_CARR_ON) == 0) { 391 tp->t_state |= TS_WOPEN; 392 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 393 ttopen, 0)) 394 break; 395 } 396 (void) spl0(); 397 398 #ifdef DEBUG 399 if (dcmdebug & DDB_OPENCLOSE) 400 printf("dcmopen: u %x st %x fl %x\n", 401 unit, tp->t_state, tp->t_flags); 402 #endif 403 if (error == 0) 404 error = (*linesw[tp->t_line].l_open)(dev, tp); 405 return (error); 406 } 407 408 /*ARGSUSED*/ 409 dcmclose(dev, flag, mode, p) 410 dev_t dev; 411 int flag, mode; 412 struct proc *p; 413 { 414 register struct tty *tp; 415 int unit; 416 417 unit = UNIT(dev); 418 tp = dcm_tty[unit]; 419 (*linesw[tp->t_line].l_close)(tp, flag); 420 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 421 (tp->t_state&TS_ISOPEN) == 0) 422 (void) dcmmctl(dev, MO_OFF, DMSET); 423 #ifdef DEBUG 424 if (dcmdebug & DDB_OPENCLOSE) 425 printf("dcmclose: u %x st %x fl %x\n", 426 unit, tp->t_state, tp->t_flags); 427 #endif 428 ttyclose(tp); 429 #if 0 430 ttyfree(tp); 431 dcm_tty[unit] = (struct tty *)0; 432 #endif 433 return (0); 434 } 435 436 dcmread(dev, uio, flag) 437 dev_t dev; 438 struct uio *uio; 439 int flag; 440 { 441 register struct tty *tp = dcm_tty[UNIT(dev)]; 442 443 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 444 } 445 446 dcmwrite(dev, uio, flag) 447 dev_t dev; 448 struct uio *uio; 449 int flag; 450 { 451 register struct tty *tp = dcm_tty[UNIT(dev)]; 452 453 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 454 } 455 456 dcmintr(brd) 457 register int brd; 458 { 459 register struct dcmdevice *dcm = dcm_addr[brd]; 460 register struct dcmischeme *dis; 461 register int unit = MKUNIT(brd, 0); 462 register int code, i; 463 int pcnd[4], mcode, mcnd[4]; 464 465 /* 466 * Do all guarded register accesses right off to minimize 467 * block out of hardware. 468 */ 469 SEM_LOCK(dcm); 470 if ((dcm->dcm_ic & IC_IR) == 0) { 471 SEM_UNLOCK(dcm); 472 return (0); 473 } 474 for (i = 0; i < 4; i++) { 475 pcnd[i] = dcm->dcm_icrtab[i].dcm_data; 476 dcm->dcm_icrtab[i].dcm_data = 0; 477 code = dcm_modem[unit+i]->mdmin; 478 if (dcmsoftCAR[brd] & FLAG_STDDCE) 479 code = hp2dce_in(code); 480 mcnd[i] = code; 481 } 482 code = dcm->dcm_iir & IIR_MASK; 483 dcm->dcm_iir = 0; /* XXX doc claims read clears interrupt?! */ 484 mcode = dcm->dcm_modemintr; 485 dcm->dcm_modemintr = 0; 486 SEM_UNLOCK(dcm); 487 488 #ifdef DEBUG 489 if (dcmdebug & DDB_INTR) { 490 printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ", 491 brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); 492 printf("miir %x mc %x/%x/%x/%x\n", 493 mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]); 494 } 495 #endif 496 if (code & IIR_TIMEO) 497 dcmrint(brd, dcm); 498 if (code & IIR_PORT0) 499 dcmpint(unit+0, pcnd[0], dcm); 500 if (code & IIR_PORT1) 501 dcmpint(unit+1, pcnd[1], dcm); 502 if (code & IIR_PORT2) 503 dcmpint(unit+2, pcnd[2], dcm); 504 if (code & IIR_PORT3) 505 dcmpint(unit+3, pcnd[3], dcm); 506 if (code & IIR_MODM) { 507 if (mcode == 0 || mcode & 0x1) /* mcode==0 -> 98642 board */ 508 dcmmint(unit+0, mcnd[0], dcm); 509 if (mcode & 0x2) 510 dcmmint(unit+1, mcnd[1], dcm); 511 if (mcode & 0x4) 512 dcmmint(unit+2, mcnd[2], dcm); 513 if (mcode & 0x8) 514 dcmmint(unit+3, mcnd[3], dcm); 515 } 516 517 dis = &dcmischeme[brd]; 518 /* 519 * Chalk up a receiver interrupt if the timer running or one of 520 * the ports reports a special character interrupt. 521 */ 522 if ((code & IIR_TIMEO) || 523 ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC)) 524 dis->dis_intr++; 525 /* 526 * See if it is time to check/change the interrupt rate. 527 */ 528 if (dcmistype < 0 && 529 (i = time.tv_sec - dis->dis_time) >= dcminterval) { 530 /* 531 * If currently per-character and averaged over 70 interrupts 532 * per-second (66 is threshold of 600 baud) in last interval, 533 * switch to timer mode. 534 * 535 * XXX decay counts ala load average to avoid spikes? 536 */ 537 if (dis->dis_perchar && dis->dis_intr > 70 * i) 538 dcmsetischeme(brd, DIS_TIMER); 539 /* 540 * If currently using timer and had more interrupts than 541 * received characters in the last interval, switch back 542 * to per-character. Note that after changing to per-char 543 * we must process any characters already in the queue 544 * since they may have arrived before the bitmap was setup. 545 * 546 * XXX decay counts? 547 */ 548 else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) { 549 dcmsetischeme(brd, DIS_PERCHAR); 550 dcmrint(brd, dcm); 551 } 552 dis->dis_intr = dis->dis_char = 0; 553 dis->dis_time = time.tv_sec; 554 } 555 return (1); 556 } 557 558 /* 559 * Port interrupt. Can be two things: 560 * First, it might be a special character (exception interrupt); 561 * Second, it may be a buffer empty (transmit interrupt); 562 */ 563 dcmpint(unit, code, dcm) 564 int unit, code; 565 struct dcmdevice *dcm; 566 { 567 struct tty *tp = dcm_tty[unit]; 568 569 if (code & IT_SPEC) 570 dcmreadbuf(unit, dcm, tp); 571 if (code & IT_TX) 572 dcmxint(unit, dcm, tp); 573 } 574 575 dcmrint(brd, dcm) 576 int brd; 577 register struct dcmdevice *dcm; 578 { 579 register int i, unit; 580 register struct tty *tp; 581 582 unit = MKUNIT(brd, 0); 583 tp = dcm_tty[unit]; 584 for (i = 0; i < 4; i++, tp++, unit++) 585 dcmreadbuf(unit, dcm, tp); 586 } 587 588 dcmreadbuf(unit, dcm, tp) 589 int unit; 590 register struct dcmdevice *dcm; 591 register struct tty *tp; 592 { 593 int port = PORT(unit); 594 register struct dcmpreg *pp = dcm_preg(dcm, port); 595 register struct dcmrfifo *fifo; 596 register int c, stat; 597 register unsigned head; 598 int nch = 0; 599 #ifdef DCMSTATS 600 struct dcmstats *dsp = &dcmstats[BOARD(unit)]; 601 602 dsp->rints++; 603 #endif 604 if ((tp->t_state & TS_ISOPEN) == 0) { 605 #ifdef KGDB 606 if ((makedev(dcmmajor, unit) == kgdb_dev) && 607 (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) && 608 dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) { 609 pp->r_head = (head + 2) & RX_MASK; 610 kgdb_connect(0); /* trap into kgdb */ 611 return; 612 } 613 #endif /* KGDB */ 614 pp->r_head = pp->r_tail & RX_MASK; 615 return; 616 } 617 618 head = pp->r_head & RX_MASK; 619 fifo = &dcm->dcm_rfifos[3-port][head>>1]; 620 /* 621 * XXX upper bound on how many chars we will take in one swallow? 622 */ 623 while (head != (pp->r_tail & RX_MASK)) { 624 /* 625 * Get character/status and update head pointer as fast 626 * as possible to make room for more characters. 627 */ 628 c = fifo->data_char; 629 stat = fifo->data_stat; 630 head = (head + 2) & RX_MASK; 631 pp->r_head = head; 632 fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0]; 633 nch++; 634 635 #ifdef DEBUG 636 if (dcmdebug & DDB_INPUT) 637 printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n", 638 unit, c&0xFF, c, stat&0xFF, 639 tp->t_flags, head, pp->r_tail); 640 #endif 641 /* 642 * Check for and handle errors 643 */ 644 if (stat & RD_MASK) { 645 #ifdef DEBUG 646 if (dcmdebug & (DDB_INPUT|DDB_SIOERR)) 647 printf("dcmreadbuf(%d): err: c%x('%c') s%x\n", 648 unit, stat, c&0xFF, c); 649 #endif 650 if (stat & (RD_BD | RD_FE)) 651 c |= TTY_FE; 652 else if (stat & RD_PE) 653 c |= TTY_PE; 654 else if (stat & RD_OVF) 655 log(LOG_WARNING, 656 "dcm%d: silo overflow\n", unit); 657 else if (stat & RD_OE) 658 log(LOG_WARNING, 659 "dcm%d: uart overflow\n", unit); 660 } 661 (*linesw[tp->t_line].l_rint)(c, tp); 662 } 663 dcmischeme[BOARD(unit)].dis_char += nch; 664 #ifdef DCMSTATS 665 dsp->rchars += nch; 666 if (nch <= DCMRBSIZE) 667 dsp->rsilo[nch]++; 668 else 669 dsp->rsilo[DCMRBSIZE+1]++; 670 #endif 671 } 672 673 dcmxint(unit, dcm, tp) 674 int unit; 675 struct dcmdevice *dcm; 676 register struct tty *tp; 677 { 678 tp->t_state &= ~TS_BUSY; 679 if (tp->t_state & TS_FLUSH) 680 tp->t_state &= ~TS_FLUSH; 681 (*linesw[tp->t_line].l_start)(tp); 682 } 683 684 dcmmint(unit, mcnd, dcm) 685 register int unit; 686 register struct dcmdevice *dcm; 687 int mcnd; 688 { 689 register struct tty *tp; 690 int delta; 691 692 #ifdef DEBUG 693 if (dcmdebug & DDB_MODEM) 694 printf("dcmmint: port %d mcnd %x mcndlast %x\n", 695 unit, mcnd, mcndlast[unit]); 696 #endif 697 tp = dcm_tty[unit]; 698 delta = mcnd ^ mcndlast[unit]; 699 mcndlast[unit] = mcnd; 700 if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) && 701 (tp->t_flags & CCTS_OFLOW)) { 702 if (mcnd & MI_CTS) { 703 tp->t_state &= ~TS_TTSTOP; 704 ttstart(tp); 705 } else 706 tp->t_state |= TS_TTSTOP; /* inline dcmstop */ 707 } 708 if (delta & MI_CD) { 709 if (mcnd & MI_CD) 710 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 711 else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 && 712 (*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 713 dcm_modem[unit]->mdmout = MO_OFF; 714 SEM_LOCK(dcm); 715 dcm->dcm_modemchng |= 1<<(unit & 3); 716 dcm->dcm_cr |= CR_MODM; 717 SEM_UNLOCK(dcm); 718 DELAY(10); /* time to change lines */ 719 } 720 } 721 } 722 723 dcmioctl(dev, cmd, data, flag, p) 724 dev_t dev; 725 int cmd; 726 caddr_t data; 727 int flag; 728 struct proc *p; 729 { 730 register struct tty *tp; 731 register int unit = UNIT(dev); 732 register struct dcmdevice *dcm; 733 register int port; 734 int error, s; 735 736 #ifdef DEBUG 737 if (dcmdebug & DDB_IOCTL) 738 printf("dcmioctl: unit %d cmd %x data %x flag %x\n", 739 unit, cmd, *data, flag); 740 #endif 741 tp = dcm_tty[unit]; 742 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 743 if (error >= 0) 744 return (error); 745 error = ttioctl(tp, cmd, data, flag, p); 746 if (error >= 0) 747 return (error); 748 749 port = PORT(unit); 750 dcm = dcm_addr[BOARD(unit)]; 751 switch (cmd) { 752 case TIOCSBRK: 753 /* 754 * Wait for transmitter buffer to empty 755 */ 756 s = spltty(); 757 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 758 DELAY(DCM_USPERCH(tp->t_ospeed)); 759 SEM_LOCK(dcm); 760 dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 761 dcm->dcm_cr |= (1 << port); /* start break */ 762 SEM_UNLOCK(dcm); 763 splx(s); 764 break; 765 766 case TIOCCBRK: 767 SEM_LOCK(dcm); 768 dcm->dcm_cmdtab[port].dcm_data |= CT_BRK; 769 dcm->dcm_cr |= (1 << port); /* end break */ 770 SEM_UNLOCK(dcm); 771 break; 772 773 case TIOCSDTR: 774 (void) dcmmctl(dev, MO_ON, DMBIS); 775 break; 776 777 case TIOCCDTR: 778 (void) dcmmctl(dev, MO_ON, DMBIC); 779 break; 780 781 case TIOCMSET: 782 (void) dcmmctl(dev, *(int *)data, DMSET); 783 break; 784 785 case TIOCMBIS: 786 (void) dcmmctl(dev, *(int *)data, DMBIS); 787 break; 788 789 case TIOCMBIC: 790 (void) dcmmctl(dev, *(int *)data, DMBIC); 791 break; 792 793 case TIOCMGET: 794 *(int *)data = dcmmctl(dev, 0, DMGET); 795 break; 796 797 default: 798 return (ENOTTY); 799 } 800 return (0); 801 } 802 803 dcmparam(tp, t) 804 register struct tty *tp; 805 register struct termios *t; 806 { 807 register struct dcmdevice *dcm; 808 register int port, mode, cflag = t->c_cflag; 809 int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); 810 811 /* check requested parameters */ 812 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 813 return (EINVAL); 814 /* and copy to tty */ 815 tp->t_ispeed = t->c_ispeed; 816 tp->t_ospeed = t->c_ospeed; 817 tp->t_cflag = cflag; 818 if (ospeed == 0) { 819 (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET); 820 return (0); 821 } 822 823 mode = 0; 824 switch (cflag&CSIZE) { 825 case CS5: 826 mode = LC_5BITS; break; 827 case CS6: 828 mode = LC_6BITS; break; 829 case CS7: 830 mode = LC_7BITS; break; 831 case CS8: 832 mode = LC_8BITS; break; 833 } 834 if (cflag&PARENB) { 835 if (cflag&PARODD) 836 mode |= LC_PODD; 837 else 838 mode |= LC_PEVEN; 839 } 840 if (cflag&CSTOPB) 841 mode |= LC_2STOP; 842 else 843 mode |= LC_1STOP; 844 #ifdef DEBUG 845 if (dcmdebug & DDB_PARAM) 846 printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n", 847 UNIT(tp->t_dev), cflag, mode, tp->t_ospeed, 848 DCM_USPERCH(tp->t_ospeed)); 849 #endif 850 851 port = PORT(tp->t_dev); 852 dcm = dcm_addr[BOARD(tp->t_dev)]; 853 /* 854 * Wait for transmitter buffer to empty. 855 */ 856 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 857 DELAY(DCM_USPERCH(tp->t_ospeed)); 858 /* 859 * Make changes known to hardware. 860 */ 861 dcm->dcm_data[port].dcm_baud = ospeed; 862 dcm->dcm_data[port].dcm_conf = mode; 863 SEM_LOCK(dcm); 864 dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 865 dcm->dcm_cr |= (1 << port); 866 SEM_UNLOCK(dcm); 867 /* 868 * Delay for config change to take place. Weighted by baud. 869 * XXX why do we do this? 870 */ 871 DELAY(16 * DCM_USPERCH(tp->t_ospeed)); 872 return (0); 873 } 874 875 void 876 dcmstart(tp) 877 register struct tty *tp; 878 { 879 register struct dcmdevice *dcm; 880 register struct dcmpreg *pp; 881 register struct dcmtfifo *fifo; 882 register char *bp; 883 register unsigned tail, next; 884 register int port, nch; 885 unsigned head; 886 char buf[16]; 887 int s; 888 #ifdef DCMSTATS 889 struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)]; 890 int tch = 0; 891 #endif 892 893 s = spltty(); 894 #ifdef DCMSTATS 895 dsp->xints++; 896 #endif 897 #ifdef DEBUG 898 if (dcmdebug & DDB_OUTPUT) 899 printf("dcmstart(%d): state %x flags %x outcc %d\n", 900 UNIT(tp->t_dev), tp->t_state, tp->t_flags, 901 tp->t_outq.c_cc); 902 #endif 903 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 904 goto out; 905 if (tp->t_outq.c_cc <= tp->t_lowat) { 906 if (tp->t_state&TS_ASLEEP) { 907 tp->t_state &= ~TS_ASLEEP; 908 wakeup((caddr_t)&tp->t_outq); 909 } 910 selwakeup(&tp->t_wsel); 911 } 912 if (tp->t_outq.c_cc == 0) { 913 #ifdef DCMSTATS 914 dsp->xempty++; 915 #endif 916 goto out; 917 } 918 919 dcm = dcm_addr[BOARD(tp->t_dev)]; 920 port = PORT(tp->t_dev); 921 pp = dcm_preg(dcm, port); 922 tail = pp->t_tail & TX_MASK; 923 next = (tail + 1) & TX_MASK; 924 head = pp->t_head & TX_MASK; 925 if (head == next) 926 goto out; 927 fifo = &dcm->dcm_tfifos[3-port][tail]; 928 again: 929 nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK); 930 #ifdef DCMSTATS 931 tch += nch; 932 #endif 933 #ifdef DEBUG 934 if (dcmdebug & DDB_OUTPUT) 935 printf("\thead %x tail %x nch %d\n", head, tail, nch); 936 #endif 937 /* 938 * Loop transmitting all the characters we can. 939 */ 940 for (bp = buf; --nch >= 0; bp++) { 941 fifo->data_char = *bp; 942 pp->t_tail = next; 943 /* 944 * If this is the first character, 945 * get the hardware moving right now. 946 */ 947 if (bp == buf) { 948 tp->t_state |= TS_BUSY; 949 SEM_LOCK(dcm); 950 dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 951 dcm->dcm_cr |= (1 << port); 952 SEM_UNLOCK(dcm); 953 } 954 tail = next; 955 fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0]; 956 next = (next + 1) & TX_MASK; 957 } 958 /* 959 * Head changed while we were loading the buffer, 960 * go back and load some more if we can. 961 */ 962 if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) { 963 #ifdef DCMSTATS 964 dsp->xrestarts++; 965 #endif 966 head = pp->t_head & TX_MASK; 967 goto again; 968 } 969 970 /* 971 * Kick it one last time in case it finished while we were 972 * loading the last bunch. 973 */ 974 if (bp > &buf[1]) { 975 tp->t_state |= TS_BUSY; 976 SEM_LOCK(dcm); 977 dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 978 dcm->dcm_cr |= (1 << port); 979 SEM_UNLOCK(dcm); 980 } 981 #ifdef DEBUG 982 if (dcmdebug & DDB_INTR) 983 printf("dcmstart(%d): head %x tail %x outqcc %d\n", 984 UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc); 985 #endif 986 out: 987 #ifdef DCMSTATS 988 dsp->xchars += tch; 989 if (tch <= DCMXBSIZE) 990 dsp->xsilo[tch]++; 991 else 992 dsp->xsilo[DCMXBSIZE+1]++; 993 #endif 994 splx(s); 995 } 996 997 /* 998 * Stop output on a line. 999 */ 1000 dcmstop(tp, flag) 1001 register struct tty *tp; 1002 int flag; 1003 { 1004 int s; 1005 1006 s = spltty(); 1007 if (tp->t_state & TS_BUSY) { 1008 /* XXX is there some way to safely stop transmission? */ 1009 if ((tp->t_state&TS_TTSTOP) == 0) 1010 tp->t_state |= TS_FLUSH; 1011 } 1012 splx(s); 1013 } 1014 1015 /* 1016 * Modem control 1017 */ 1018 dcmmctl(dev, bits, how) 1019 dev_t dev; 1020 int bits, how; 1021 { 1022 register struct dcmdevice *dcm; 1023 int s, unit, brd, hit = 0; 1024 1025 unit = UNIT(dev); 1026 #ifdef DEBUG 1027 if (dcmdebug & DDB_MODEM) 1028 printf("dcmmctl(%d) unit %d bits 0x%x how %x\n", 1029 BOARD(unit), unit, bits, how); 1030 #endif 1031 1032 brd = BOARD(unit); 1033 dcm = dcm_addr[brd]; 1034 s = spltty(); 1035 switch (how) { 1036 1037 case DMSET: 1038 dcm_modem[unit]->mdmout = bits; 1039 hit++; 1040 break; 1041 1042 case DMBIS: 1043 dcm_modem[unit]->mdmout |= bits; 1044 hit++; 1045 break; 1046 1047 case DMBIC: 1048 dcm_modem[unit]->mdmout &= ~bits; 1049 hit++; 1050 break; 1051 1052 case DMGET: 1053 bits = dcm_modem[unit]->mdmin; 1054 if (dcmsoftCAR[brd] & FLAG_STDDCE) 1055 bits = hp2dce_in(bits); 1056 break; 1057 } 1058 if (hit) { 1059 SEM_LOCK(dcm); 1060 dcm->dcm_modemchng |= 1<<(unit & 3); 1061 dcm->dcm_cr |= CR_MODM; 1062 SEM_UNLOCK(dcm); 1063 DELAY(10); /* delay until done */ 1064 (void) splx(s); 1065 } 1066 return (bits); 1067 } 1068 1069 /* 1070 * Set board to either interrupt per-character or at a fixed interval. 1071 */ 1072 dcmsetischeme(brd, flags) 1073 int brd, flags; 1074 { 1075 register struct dcmdevice *dcm = dcm_addr[brd]; 1076 register struct dcmischeme *dis = &dcmischeme[brd]; 1077 register int i; 1078 u_char mask; 1079 int perchar = flags & DIS_PERCHAR; 1080 1081 #ifdef DEBUG 1082 if (dcmdebug & DDB_INTSCHM) 1083 printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n", 1084 brd, perchar, dis->dis_perchar, 1085 dis->dis_intr, dis->dis_char); 1086 if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) { 1087 printf("dcmsetischeme(%d): redundent request %d\n", 1088 brd, perchar); 1089 return; 1090 } 1091 #endif 1092 /* 1093 * If perchar is non-zero, we enable interrupts on all characters 1094 * otherwise we disable perchar interrupts and use periodic 1095 * polling interrupts. 1096 */ 1097 dis->dis_perchar = perchar; 1098 mask = perchar ? 0xf : 0x0; 1099 for (i = 0; i < 256; i++) 1100 dcm->dcm_bmap[i].data_data = mask; 1101 /* 1102 * Don't slow down tandem mode, interrupt on flow control 1103 * chars for any port on the board. 1104 */ 1105 if (!perchar) { 1106 register struct tty *tp = dcm_tty[MKUNIT(brd, 0)]; 1107 int c; 1108 1109 for (i = 0; i < 4; i++, tp++) { 1110 if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE) 1111 dcm->dcm_bmap[c].data_data |= (1 << i); 1112 if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE) 1113 dcm->dcm_bmap[c].data_data |= (1 << i); 1114 } 1115 } 1116 /* 1117 * Board starts with timer disabled so if first call is to 1118 * set perchar mode then we don't want to toggle the timer. 1119 */ 1120 if (flags == (DIS_RESET|DIS_PERCHAR)) 1121 return; 1122 /* 1123 * Toggle card 16.7ms interrupts (we first make sure that card 1124 * has cleared the bit so it will see the toggle). 1125 */ 1126 while (dcm->dcm_cr & CR_TIMER) 1127 ; 1128 SEM_LOCK(dcm); 1129 dcm->dcm_cr |= CR_TIMER; 1130 SEM_UNLOCK(dcm); 1131 } 1132 1133 /* 1134 * Following are all routines needed for DCM to act as console 1135 */ 1136 #include <dev/cons.h> 1137 1138 dcmcnprobe(cp) 1139 struct consdev *cp; 1140 { 1141 register struct hp_hw *hw; 1142 int unit; 1143 1144 /* locate the major number */ 1145 for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++) 1146 if (cdevsw[dcmmajor].d_open == dcmopen) 1147 break; 1148 1149 /* 1150 * Implicitly assigns the lowest select code DCM card found to be 1151 * logical unit 0 (actually CONUNIT). If your config file does 1152 * anything different, you're screwed. 1153 */ 1154 for (hw = sc_table; hw->hw_type; hw++) 1155 if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva)) 1156 break; 1157 if (!HW_ISDEV(hw, D_COMMDCM)) { 1158 cp->cn_pri = CN_DEAD; 1159 return; 1160 } 1161 unit = CONUNIT; 1162 dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva; 1163 1164 /* initialize required fields */ 1165 cp->cn_dev = makedev(dcmmajor, unit); 1166 switch (dcm_addr[BOARD(unit)]->dcm_rsid) { 1167 case DCMID: 1168 cp->cn_pri = CN_NORMAL; 1169 break; 1170 case DCMID|DCMCON: 1171 cp->cn_pri = CN_REMOTE; 1172 break; 1173 default: 1174 cp->cn_pri = CN_DEAD; 1175 return; 1176 } 1177 /* 1178 * If dcmconsole is initialized, raise our priority. 1179 */ 1180 if (dcmconsole == UNIT(unit)) 1181 cp->cn_pri = CN_REMOTE; 1182 #ifdef KGDB_CHEAT 1183 /* 1184 * This doesn't currently work, at least not with ite consoles; 1185 * the console hasn't been initialized yet. 1186 */ 1187 if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) { 1188 (void) dcminit(kgdb_dev, kgdb_rate); 1189 if (kgdb_debug_init) { 1190 /* 1191 * We assume that console is ready for us... 1192 * this assumes that a dca or ite console 1193 * has been selected already and will init 1194 * on the first putc. 1195 */ 1196 printf("dcm%d: ", UNIT(kgdb_dev)); 1197 kgdb_connect(1); 1198 } 1199 } 1200 #endif 1201 } 1202 1203 dcmcninit(cp) 1204 struct consdev *cp; 1205 { 1206 dcminit(cp->cn_dev, dcmdefaultrate); 1207 dcmconsinit = 1; 1208 dcmconsole = UNIT(cp->cn_dev); 1209 } 1210 1211 dcminit(dev, rate) 1212 dev_t dev; 1213 int rate; 1214 { 1215 register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 1216 int s, mode, port; 1217 1218 port = PORT(dev); 1219 mode = LC_8BITS | LC_1STOP; 1220 s = splhigh(); 1221 /* 1222 * Wait for transmitter buffer to empty. 1223 */ 1224 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 1225 DELAY(DCM_USPERCH(rate)); 1226 /* 1227 * Make changes known to hardware. 1228 */ 1229 dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab); 1230 dcm->dcm_data[port].dcm_conf = mode; 1231 SEM_LOCK(dcm); 1232 dcm->dcm_cmdtab[port].dcm_data |= CT_CON; 1233 dcm->dcm_cr |= (1 << port); 1234 SEM_UNLOCK(dcm); 1235 /* 1236 * Delay for config change to take place. Weighted by baud. 1237 * XXX why do we do this? 1238 */ 1239 DELAY(16 * DCM_USPERCH(rate)); 1240 splx(s); 1241 } 1242 1243 dcmcngetc(dev) 1244 dev_t dev; 1245 { 1246 register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 1247 register struct dcmrfifo *fifo; 1248 register struct dcmpreg *pp; 1249 register unsigned head; 1250 int s, c, stat, port; 1251 1252 port = PORT(dev); 1253 pp = dcm_preg(dcm, port); 1254 s = splhigh(); 1255 head = pp->r_head & RX_MASK; 1256 fifo = &dcm->dcm_rfifos[3-port][head>>1]; 1257 while (head == (pp->r_tail & RX_MASK)) 1258 ; 1259 /* 1260 * If board interrupts are enabled, just let our received char 1261 * interrupt through in case some other port on the board was 1262 * busy. Otherwise we must clear the interrupt. 1263 */ 1264 SEM_LOCK(dcm); 1265 if ((dcm->dcm_ic & IC_IE) == 0) 1266 stat = dcm->dcm_iir; 1267 SEM_UNLOCK(dcm); 1268 c = fifo->data_char; 1269 stat = fifo->data_stat; 1270 pp->r_head = (head + 2) & RX_MASK; 1271 splx(s); 1272 return (c); 1273 } 1274 1275 /* 1276 * Console kernel output character routine. 1277 */ 1278 dcmcnputc(dev, c) 1279 dev_t dev; 1280 int c; 1281 { 1282 register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 1283 register struct dcmpreg *pp; 1284 unsigned tail; 1285 int s, port, stat; 1286 1287 port = PORT(dev); 1288 pp = dcm_preg(dcm, port); 1289 s = splhigh(); 1290 #ifdef KGDB 1291 if (dev != kgdb_dev) 1292 #endif 1293 if (dcmconsinit == 0) { 1294 (void) dcminit(dev, dcmdefaultrate); 1295 dcmconsinit = 1; 1296 } 1297 tail = pp->t_tail & TX_MASK; 1298 while (tail != (pp->t_head & TX_MASK)) 1299 ; 1300 dcm->dcm_tfifos[3-port][tail].data_char = c; 1301 pp->t_tail = tail = (tail + 1) & TX_MASK; 1302 SEM_LOCK(dcm); 1303 dcm->dcm_cmdtab[port].dcm_data |= CT_TX; 1304 dcm->dcm_cr |= (1 << port); 1305 SEM_UNLOCK(dcm); 1306 while (tail != (pp->t_head & TX_MASK)) 1307 ; 1308 /* 1309 * If board interrupts are enabled, just let our completion 1310 * interrupt through in case some other port on the board 1311 * was busy. Otherwise we must clear the interrupt. 1312 */ 1313 if ((dcm->dcm_ic & IC_IE) == 0) { 1314 SEM_LOCK(dcm); 1315 stat = dcm->dcm_iir; 1316 SEM_UNLOCK(dcm); 1317 } 1318 splx(s); 1319 } 1320 #endif 1321