1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: $Hdr: dcm.c 1.17 89/10/01$ 13 * 14 * @(#)dcm.c 7.1 (Berkeley) 05/08/90 15 */ 16 17 /* 18 * Console support is not finished. 19 */ 20 21 #include "dcm.h" 22 #if NDCM > 0 23 /* 24 * 98642/MUX 25 */ 26 #include "param.h" 27 #include "systm.h" 28 #include "ioctl.h" 29 #include "tty.h" 30 #include "user.h" 31 #include "conf.h" 32 #include "file.h" 33 #include "uio.h" 34 #include "kernel.h" 35 #include "syslog.h" 36 #include "time.h" 37 38 #include "device.h" 39 #include "dcmreg.h" 40 #include "machine/cpu.h" 41 #include "machine/isr.h" 42 43 int dcmprobe(); 44 struct driver dcmdriver = { 45 dcmprobe, "dcm", 46 }; 47 48 #define NDCMLINE (NDCM*4) 49 50 int dcmstart(), dcmparam(), dcmintr(); 51 int dcmsoftCAR[NDCM]; 52 int dcmintschm[NDCM]; 53 int dcm_active; 54 int ndcm = NDCM; 55 int dcmconsole = -1; 56 struct dcmdevice *dcm_addr[NDCM]; 57 struct tty dcm_tty[NDCMLINE]; 58 int dcm_cnt = NDCMLINE; 59 struct isr dcmisr[NDCM]; 60 int dcmintrval = 5; /* rate in secs that interschem is examined */ 61 long dcmbang[NDCM]; 62 int dcmchrrd[NDCM]; /* chars read during each sample time */ 63 int dcmintrocc[NDCM]; /* # of interrupts for each sample time */ 64 65 66 struct speedtab dcmspeedtab[] = { 67 0, BR_0, 68 50, BR_50, 69 75, BR_75, 70 110, BR_110, 71 134, BR_134, 72 150, BR_150, 73 300, BR_300, 74 600, BR_600, 75 1200, BR_1200, 76 1800, BR_1800, 77 2400, BR_2400, 78 4800, BR_4800, 79 9600, BR_9600, 80 19200, BR_19200, 81 38400, BR_38400, 82 -1, -1 83 }; 84 85 #ifdef DEBUG 86 int dcmdebug = 0x00; 87 #define DDB_SIOERR 0x01 88 #define DDB_PARAM 0x02 89 #define DDB_INPUT 0x04 90 #define DDB_OUTPUT 0x08 91 #define DDB_INTR 0x10 92 #define DDB_IOCTL 0x20 93 #define DDB_INTSCHM 0x40 94 #define DDB_MOD 0x80 95 #define DDB_OPENCLOSE 0x100 96 97 long unsigned int dcmrsize[33]; /* read sizes, 32 for over 31, 0 for 0 */ 98 #endif 99 100 extern struct tty *constty; 101 102 #define UNIT(x) minor(x) 103 #define BOARD(x) ((x) >> 2) 104 #define PORT(x) ((x) & 3) 105 #define MKUNIT(b,p) (((b) << 2) | (p)) 106 107 dcmprobe(hd) 108 register struct hp_device *hd; 109 { 110 register struct dcmdevice *dcm; 111 register int i; 112 register int timo = 0; 113 int s, brd; 114 115 dcm = (struct dcmdevice *)hd->hp_addr; 116 if ((dcm->dcm_rsid & 0x1f) != DCMID) 117 return (0); 118 brd = hd->hp_unit; 119 s = spltty(); 120 dcm->dcm_rsid = DCMRS; 121 DELAY(50000); /* 5000 is not long enough */ 122 dcm->dcm_rsid = 0; 123 dcm->dcm_ic = IC_IE; 124 dcm->dcm_cr = CR_SELFT; 125 while ((dcm->dcm_ic & IC_IR) == 0) { 126 if (++timo == 20000) { 127 printf("dcm%d: timeout on selftest interrupt\n", brd); 128 printf("dcm%d:rsid %x, ic %x, cr %x, iir %x\n", 129 brd, dcm->dcm_rsid, dcm->dcm_ic, 130 dcm->dcm_cr, dcm->dcm_iir); 131 return(0); 132 } 133 } 134 DELAY(50000) /* XXX why is this needed ???? */ 135 while ((dcm->dcm_iir & IIR_SELFT) == 0) { 136 if (++timo == 400000) { 137 printf("dcm%d: timeout on selftest\n", brd); 138 printf("dcm%d:rsid %x, ic %x, cr %x, iir %x\n", 139 brd, dcm->dcm_rsid, dcm->dcm_ic, 140 dcm->dcm_cr, dcm->dcm_iir); 141 return(0); 142 } 143 } 144 DELAY(50000) /* XXX why is this needed ???? */ 145 if (dcm->dcm_stcon != ST_OK) { 146 printf("dcm%d: self test failed: %x\n", brd, dcm->dcm_stcon); 147 return(0); 148 } 149 dcm->dcm_ic = IC_ID; 150 splx(s); 151 152 hd->hp_ipl = DCMIPL(dcm->dcm_ic); 153 dcmisr[brd].isr_ipl = hd->hp_ipl; 154 dcmisr[brd].isr_arg = brd; 155 dcmisr[brd].isr_intr = dcmintr; 156 dcm_addr[brd] = dcm; 157 dcm_active |= 1 << brd; 158 dcmsoftCAR[brd] = hd->hp_flags; 159 dcmintschm[brd] = 1; /* start with interrupt/char */ 160 for (i = 0; i < 256; i++) 161 dcm->dcm_bmap[i].data_data = 0x0f; 162 dcmintrocc[brd] = 0; 163 dcmchrrd[brd] = 0; 164 isrlink(&dcmisr[brd]); 165 dcm->dcm_mdmmsk = MI_CD; /* Enable carrier detect interrupts */ 166 dcm->dcm_ic = IC_IE; /* turn interrupts on */ 167 /* 168 * Need to reset baud rate, etc. of next print so reset dcmconsole. 169 * Also make sure console is always "hardwired" 170 */ 171 if (brd == BOARD(dcmconsole)) { 172 dcmsoftCAR[brd] |= (1 << PORT(dcmconsole)); 173 dcmconsole = -1; 174 } 175 return (1); 176 } 177 178 dcmopen(dev, flag) 179 dev_t dev; 180 { 181 register struct tty *tp; 182 register int unit, brd; 183 184 unit = UNIT(dev); 185 brd = BOARD(unit); 186 dcmbang[brd] = time.tv_sec; /* for interrupt scheme */ 187 if (unit >= dcm_cnt || (dcm_active & (1 << brd)) == 0) 188 return (ENXIO); 189 tp = &dcm_tty[unit]; 190 tp->t_oproc = dcmstart; 191 tp->t_param = dcaparam; 192 tp->t_dev = dev; 193 if ((tp->t_state & TS_ISOPEN) == 0) { 194 ttychars(tp); 195 tp->t_iflag = TTYDEF_IFLAG; 196 tp->t_oflag = TTYDEF_OFLAG; 197 tp->t_cflag = TTYDEF_CFLAG; 198 tp->t_lflag = TTYDEF_LFLAG; 199 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 200 dcmparam(tp, &tp->t_termios); 201 ttsetwater(tp); 202 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 203 return (EBUSY); 204 if (PORT(unit) == 0) /* enable port 0 */ 205 (void) dcmmctl(dev, MO_ON, DMSET); 206 if (dcmsoftCAR[brd] & (1 << PORT(unit))) 207 tp->t_state |= TS_CARR_ON; 208 else if (PORT(unit)) /* Only port 0 has modem control */ 209 tp->t_state |= TS_CARR_ON; 210 else if (dcmmctl(dev, MO_OFF, DMGET) & MI_CD) 211 tp->t_state |= TS_CARR_ON; 212 (void) spltty(); 213 while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) && 214 (tp->t_state & TS_CARR_ON) == 0) { 215 tp->t_state |= TS_WOPEN; 216 sleep((caddr_t)&tp->t_rawq, TTIPRI); 217 } 218 (void) spl0(); 219 220 #ifdef DEBUG 221 if (dcmdebug & DDB_OPENCLOSE) 222 printf("dcmopen: u %x st %x fl %x\n", 223 unit, tp->t_state, tp->t_flags); 224 #endif 225 return ((*linesw[tp->t_line].l_open)(dev, tp)); 226 } 227 228 /*ARGSUSED*/ 229 dcmclose(dev, flag) 230 dev_t dev; 231 { 232 register struct tty *tp; 233 int unit; 234 235 unit = UNIT(dev); 236 tp = &dcm_tty[unit]; 237 (*linesw[tp->t_line].l_close)(tp); 238 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 239 (tp->t_state&TS_ISOPEN) == 0) 240 (void) dcmmctl(dev, MO_OFF, DMSET); 241 #ifdef DEBUG 242 if (dcmdebug & DDB_OPENCLOSE) 243 printf("dcmclose: u %x st %x fl %x\n", 244 unit, tp->t_state, tp->t_flags); 245 #endif 246 ttyclose(tp); 247 return(0); 248 } 249 250 dcmread(dev, uio, flag) 251 dev_t dev; 252 struct uio *uio; 253 { 254 register struct tty *tp; 255 256 tp = &dcm_tty[UNIT(dev)]; 257 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 258 } 259 260 dcmwrite(dev, uio, flag) 261 dev_t dev; 262 struct uio *uio; 263 { 264 int unit = UNIT(dev); 265 register struct tty *tp; 266 267 tp = &dcm_tty[unit]; 268 if (unit == dcmconsole && constty && 269 (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN)) 270 tp = constty; 271 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 272 } 273 274 dcmintr(brd) 275 register int brd; 276 { 277 register struct dcmdevice *dcm; 278 int i, code, pcnd[4], mcnd, delta; 279 280 dcm = dcm_addr[brd]; 281 SEM_LOCK(dcm); 282 if ((dcm->dcm_ic & IC_IR) == 0) { 283 SEM_UNLOCK(dcm); 284 return(0); 285 } 286 for (i = 0; i < 4; i++) { 287 pcnd[i] = dcm->dcm_icrtab[i].dcm_data; 288 dcm->dcm_icrtab[i].dcm_data = 0; 289 } 290 mcnd = dcm->dcm_mdmin; 291 code = dcm->dcm_iir & IIR_MASK; 292 dcm->dcm_iir = 0; 293 SEM_UNLOCK(dcm); 294 295 #ifdef DEBUG 296 if (dcmdebug & DDB_INTR) 297 printf("dcmintr: iir %x p0 %x p1 %x p2 %x p3 %x m %x\n", 298 code, pcnd[0], pcnd[1], pcnd[2], 299 pcnd[3], mcnd); 300 #endif 301 if (code & IIR_PORT0) 302 dcmpint(MKUNIT(brd, 0), pcnd[0], dcm); 303 if (code & IIR_PORT1) 304 dcmpint(MKUNIT(brd, 1), pcnd[1], dcm); 305 if (code & IIR_PORT2) 306 dcmpint(MKUNIT(brd, 2), pcnd[2], dcm); 307 if (code & IIR_PORT3) 308 dcmpint(MKUNIT(brd, 3), pcnd[3], dcm); 309 if (code & IIR_MODM) 310 dcmmint(MKUNIT(brd, 0), mcnd, dcm); /* always port 0 */ 311 if (code & IIR_TIMEO) 312 dcmrint(brd, dcm); 313 314 /* 315 * See if need to change interrupt rate. 316 * 16.7ms is the polling interrupt rate. 317 * Reference: 16.7ms is about 550 buad; 38.4k is 72 chars in 16.7ms 318 */ 319 if ((delta = time.tv_sec - dcmbang[brd]) >= dcmintrval) { 320 dcmbang[brd] = time.tv_sec; 321 /* 322 * 66 threshold of 600 buad, use 70 323 */ 324 if (dcmintschm[brd] && dcmintrocc[brd] > 70 * delta) 325 dcm_setintrschm(dcm, 0, brd); 326 else if (!dcmintschm[brd] && dcmintrocc[brd] > dcmchrrd[brd]) { 327 dcm_setintrschm(dcm, 1, brd); 328 /* 329 * Must check the receive queue after switch 330 * from polling mode to interrupt/char 331 */ 332 dcmrint(brd, dcm); 333 } 334 dcmintrocc[brd] = 0; 335 dcmchrrd[brd] = 0; 336 } else 337 dcmintrocc[brd]++; 338 339 return(1); 340 } 341 342 /* 343 * Port interrupt. Can be two things: 344 * First, it might be a special character (exception interrupt); 345 * Second, it may be a buffer empty (transmit interrupt); 346 */ 347 dcmpint(unit, code, dcm) 348 int unit, code; 349 register struct dcmdevice *dcm; 350 { 351 register struct tty *tp; 352 register int port = PORT(unit); 353 354 if (code & IT_SPEC) { 355 tp = &dcm_tty[unit]; 356 if ((tp->t_state & TS_ISOPEN) != 0) 357 dcmreadbuf(unit, dcm, tp, port); 358 else 359 dcm->dcm_rhead[port].ptr = dcm->dcm_rtail[port].ptr & RX_MASK; 360 } 361 if (code & IT_TX) 362 dcmxint(unit, dcm); 363 } 364 365 dcmrint(brd, dcm) 366 int brd; 367 register struct dcmdevice *dcm; 368 { 369 register struct tty *tp; 370 register int i, unit; 371 372 unit = MKUNIT(brd, 0); 373 tp = &dcm_tty[unit]; 374 for (i = 0; i < 4; i++, tp++, unit++) { 375 /* TS_WOPEN catch race when switching to polling mode */ 376 if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) != 0) 377 dcmreadbuf(unit, dcm, tp, i); 378 else 379 dcm->dcm_rhead[i].ptr = dcm->dcm_rtail[i].ptr & RX_MASK; 380 } 381 } 382 383 dcmreadbuf(unit, dcm, tp, port) 384 int unit; 385 register struct dcmdevice *dcm; 386 register struct tty *tp; 387 register int port; 388 { 389 register int c, stat; 390 register unsigned head; 391 unsigned tail; 392 #ifdef DEBUG 393 int silocnt; 394 silocnt = 0; 395 #endif /* DEBUG */ 396 397 readrestart: 398 head = dcm->dcm_rhead[port].ptr & RX_MASK; 399 tail = dcm->dcm_rtail[port].ptr & RX_MASK; 400 401 while (head != tail) { 402 c = dcm->dcm_rfifos[3 - port][head / 2].data_char; 403 stat = dcm->dcm_rfifos[3 - port][head / 2].data_stat; 404 dcmchrrd[BOARD(unit)]++; 405 #ifdef DEBUG 406 silocnt++; 407 #endif 408 head = (head + 2) & RX_MASK; 409 dcm->dcm_rhead[port].ptr = head; 410 411 #ifdef DEBUG 412 if (dcmdebug & DDB_INPUT) 413 printf("dcmreadbuf: u%d p%d c%x s%x f%x h%x t%x char %c\n", 414 BOARD(unit), PORT(unit), c&0xFF, stat&0xFF, 415 tp->t_flags, head, tail, c); 416 #endif 417 if (stat & RD_MASK) { /* Check for errors */ 418 #ifdef DEBUG 419 if (dcmdebug & DDB_INPUT || dcmdebug & DDB_SIOERR) 420 printf("dcm%d port%d: data error: stat 0x%x data 0x%x chr %c\n", 421 BOARD(unit), PORT(unit), stat, c, c); 422 #endif 423 if (stat & (RD_BD | RD_FE)) 424 c |= TTY_FE; 425 else if (stat & RD_PE) 426 c |= TTY_PE; 427 else if (stat & RD_OVF) 428 log(LOG_WARNING, 429 "dcm%d port%d: silo overflow\n", 430 BOARD(unit), PORT(unit)); 431 else if (stat & RD_OE) 432 log(LOG_WARNING, 433 "dcm%d port%d: uart overflow\n", 434 BOARD(unit), PORT(unit)); 435 } 436 (*linesw[tp->t_line].l_rint)(c, tp); 437 } 438 /* for higher speed need to processes everything that might 439 * have arrived since we started; see if tail changed */ 440 if (tail != dcm->dcm_rtail[port].ptr & RX_MASK) 441 goto readrestart; 442 443 #ifdef DEBUG 444 if (silocnt < 33) 445 dcmrsize[silocnt]++; 446 else 447 dcmrsize[32]++; 448 #endif 449 } 450 451 dcmxint(unit, dcm) 452 int unit; 453 struct dcmdevice *dcm; 454 { 455 register struct tty *tp; 456 457 tp = &dcm_tty[unit]; 458 tp->t_state &= ~TS_BUSY; 459 if (tp->t_state & TS_FLUSH) 460 tp->t_state &= ~TS_FLUSH; 461 if (tp->t_line) 462 (*linesw[tp->t_line].l_start)(tp); 463 else 464 dcmstart(tp); 465 } 466 467 dcmmint(unit, mcnd, dcm) 468 register int unit; 469 register struct dcmdevice *dcm; 470 int mcnd; 471 { 472 register struct tty *tp; 473 474 #ifdef DEBUG 475 if (dcmdebug & DDB_MOD) 476 printf("dcmmint: unit %x mcnd %x\n", unit, mcnd); 477 #endif DEBUG 478 tp = &dcm_tty[unit]; 479 if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0) { 480 if (mcnd & MI_CD) 481 (void) (*linesw[tp->t_line].l_modem)(tp, 1); 482 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) { 483 dcm->dcm_mdmout &= ~(MO_DTR | MO_RTS); 484 SEM_LOCK(dcm); 485 dcm->dcm_cr |= CR_MODM; 486 SEM_UNLOCK(dcm); 487 } 488 } 489 } 490 491 dcmioctl(dev, cmd, data, flag) 492 dev_t dev; 493 caddr_t data; 494 { 495 register struct tty *tp; 496 register int unit = UNIT(dev); 497 register struct dcmdevice *dcm; 498 register int port; 499 int error; 500 501 #ifdef DEBUG 502 if (dcmdebug & DDB_IOCTL) 503 printf("dcmioctl: unit %d cmd %x data %x flag %x\n", 504 unit, cmd, *data, flag); 505 #endif 506 tp = &dcm_tty[unit]; 507 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 508 if (error >= 0) 509 return (error); 510 error = ttioctl(tp, cmd, data, flag); 511 if (error >= 0) 512 return (error); 513 514 port = PORT(unit); 515 dcm = dcm_addr[BOARD(unit)]; 516 switch (cmd) { 517 case TIOCSBRK: 518 dcm->dcm_cmdtab[port].dcm_data = CT_BRK; 519 SEM_LOCK(dcm); 520 dcm->dcm_cr = (1 << port); /* start break */ 521 SEM_UNLOCK(dcm); 522 break; 523 524 case TIOCCBRK: 525 dcm->dcm_cmdtab[port].dcm_data = CT_BRK; 526 SEM_LOCK(dcm); 527 dcm->dcm_cr = (1 << port); /* end break */ 528 SEM_UNLOCK(dcm); 529 break; 530 531 case TIOCSDTR: 532 (void) dcmmctl(dev, MO_ON, DMBIS); 533 break; 534 535 case TIOCCDTR: 536 (void) dcmmctl(dev, MO_ON, DMBIC); 537 break; 538 539 case TIOCMSET: 540 (void) dcmmctl(dev, *(int *)data, DMSET); 541 break; 542 543 case TIOCMBIS: 544 (void) dcmmctl(dev, *(int *)data, DMBIS); 545 break; 546 547 case TIOCMBIC: 548 (void) dcmmctl(dev, *(int *)data, DMBIC); 549 break; 550 551 case TIOCMGET: 552 *(int *)data = dcmmctl(dev, 0, DMGET); 553 break; 554 555 default: 556 return (ENOTTY); 557 } 558 return (0); 559 } 560 561 dcmparam(tp, t) 562 register struct tty *tp; 563 register struct termios *t; 564 { 565 register struct dcmdevice *dcm; 566 register int mode, cflag = t->c_cflag; 567 register int port; 568 int unit = UNIT(tp->t_dev); 569 int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab); 570 571 /* check requested parameters */ 572 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 573 return(EINVAL); 574 /* and copy to tty */ 575 tp->t_ispeed = t->c_ispeed; 576 tp->t_ospeed = t->c_ospeed; 577 tp->t_cflag = cflag; 578 579 dcm = dcm_addr[BOARD(unit)]; 580 if (ospeed == 0) { 581 (void) dcmmctl(unit, MO_OFF, DMSET); /* hang up line */ 582 return; 583 } 584 port = PORT(unit); 585 dcm->dcm_data[port].dcm_baud = ospeed; 586 switch (cflag&CSIZE) { 587 case CS5: 588 mode = LC_5BITS; break; 589 case CS6: 590 mode = LC_6BITS; break; 591 case CS7: 592 mode = LC_7BITS; break; 593 case CS8: 594 mode = LC_8BITS; break; 595 } 596 if (cflag&PARENB) { 597 if (cflag&PARODD) 598 mode |= LC_PODD; 599 else 600 mode |= LC_PEVEN; 601 } 602 if (cflag&CSTOPB) 603 mode |= LC_2STOP; 604 else 605 mode |= LC_1STOP; 606 #ifdef DEBUG 607 if (dcmdebug & DDB_PARAM) 608 printf("dcmparam: unit %d cflag %x mode %x speed %x\n", 609 unit, cflag, mode, ospeed); 610 #endif 611 /* wait for transmitter buffer to empty */ 612 while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr) 613 ; 614 615 dcm->dcm_data[port].dcm_conf = mode; 616 dcm->dcm_cmdtab[port].dcm_data = CT_CON; 617 SEM_LOCK(dcm); 618 dcm->dcm_cr = (1 << port); 619 SEM_UNLOCK(dcm); 620 } 621 622 dcmstart(tp) 623 register struct tty *tp; 624 { 625 register struct dcmdevice *dcm; 626 int s, unit, c; 627 register int tail, next, head, port; 628 int restart = 0, nch = 0; 629 630 unit = UNIT(tp->t_dev); 631 port = PORT(unit); 632 dcm = dcm_addr[BOARD(unit)]; 633 s = spltty(); 634 #ifdef DEBUG 635 if (dcmdebug & DDB_OUTPUT) 636 printf("dcmstart: unit %d state %x flags %x outcc %d\n", 637 unit, tp->t_state, tp->t_flags, tp->t_outq.c_cc); 638 #endif 639 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 640 goto out; 641 if (tp->t_outq.c_cc <= tp->t_lowat) { 642 if (tp->t_state&TS_ASLEEP) { 643 tp->t_state &= ~TS_ASLEEP; 644 wakeup((caddr_t)&tp->t_outq); 645 } 646 if (tp->t_wsel) { 647 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 648 tp->t_wsel = 0; 649 tp->t_state &= ~TS_WCOLL; 650 } 651 } 652 tail = dcm->dcm_ttail[port].ptr & TX_MASK; 653 next = (dcm->dcm_ttail[port].ptr + 1) & TX_MASK; 654 head = dcm->dcm_thead[port].ptr & TX_MASK; 655 #ifdef DEBUG 656 if (dcmdebug & DDB_OUTPUT) 657 printf("\thead %x tail %x next %x\n", 658 head, tail, next); 659 #endif 660 if (tail == head && tp->t_outq.c_cc) 661 restart++; 662 while (tp->t_outq.c_cc && next != head) { 663 nch++; 664 c = getc(&tp->t_outq); 665 dcm->dcm_tfifos[3 - port][tail].data_char = c; 666 dcm->dcm_ttail[port].ptr = next; 667 tail = next; 668 next = (tail + 1) & TX_MASK; 669 } 670 if (restart && nch) { 671 tp->t_state |= TS_BUSY; 672 SEM_LOCK(dcm); 673 #ifdef DEBUG 674 if (dcmdebug & DDB_INTR) 675 printf("TX on port %d head %x tail %x cc %d\n", 676 port, tail, head, tp->t_outq.c_cc); 677 #endif 678 dcm->dcm_cmdtab[port].dcm_data = CT_TX; 679 dcm->dcm_cr = (1 << port); 680 SEM_UNLOCK(dcm); 681 } 682 out: 683 splx(s); 684 } 685 686 /* 687 * Stop output on a line. 688 */ 689 dcmstop(tp, flag) 690 register struct tty *tp; 691 { 692 int s; 693 694 s = spltty(); 695 if (tp->t_state & TS_BUSY) { 696 if ((tp->t_state&TS_TTSTOP)==0) 697 tp->t_state |= TS_FLUSH; 698 } 699 splx(s); 700 } 701 702 /* Modem control */ 703 704 dcmmctl(dev, bits, how) 705 dev_t dev; 706 int bits, how; 707 { 708 register struct dcmdevice *dcm; 709 int s, hit = 0; 710 711 /* Only port 0 has modem control lines. For right now the following */ 712 /* is ok, but needs to changed for the 8 port board. */ 713 if (PORT(UNIT(dev)) != 0) 714 return(bits); 715 716 dcm = dcm_addr[BOARD(UNIT(dev))]; 717 s = spltty(); 718 switch (how) { 719 720 case DMSET: 721 dcm->dcm_mdmout = bits; 722 hit++; 723 break; 724 725 case DMBIS: 726 dcm->dcm_mdmout |= bits; 727 hit++; 728 break; 729 730 case DMBIC: 731 dcm->dcm_mdmout &= ~bits; 732 hit++; 733 break; 734 735 case DMGET: 736 bits = dcm->dcm_mdmin; 737 break; 738 } 739 if (hit) { 740 SEM_LOCK(dcm); 741 dcm->dcm_cr |= CR_MODM; 742 SEM_UNLOCK(dcm); 743 (void) splx(s); 744 } 745 return(bits); 746 } 747 748 dcm_setintrschm(dcm, request, brd) 749 register struct dcmdevice *dcm; 750 int request, brd; 751 { 752 register int i; 753 754 #ifdef DEBUG 755 if (dcmdebug & DDB_INTSCHM) { 756 printf("dcm%d set intr schm request %d int state %x silo hist \n\t", 757 brd, request, dcmintschm[brd]); 758 for (i = 0; i < 33; i++) { 759 printf(" %u", dcmrsize[i]); 760 dcmrsize[i] = 0; 761 } 762 printf("\n"); 763 } 764 #endif /* DEBUG */ 765 766 /* if request true then we interrupt per char, else use card */ 767 /* polling interrupt hardware */ 768 #ifdef DEBUG 769 if (request == dcmintschm[brd]) { 770 printf("dcm%d setintrschm redundent request %x current %x\n", 771 brd, request, dcmintschm[brd]); 772 return; 773 } 774 #endif /* DEBUG */ 775 if (request) { 776 for (i = 0; i < 256; i++) 777 dcm->dcm_bmap[i].data_data = 0x0f; 778 dcmintschm[brd] = 1; 779 } 780 else { 781 for (i = 0; i < 256; i++) 782 dcm->dcm_bmap[i].data_data = 0x00; 783 /* 784 * Don't slow down tandem mode, interrupt on these chars. 785 * XXX bad assumption, everyone uses ^Q, ^S for flow 786 */ 787 dcm->dcm_bmap[0x11].data_data = 0x0f; 788 dcm->dcm_bmap[0x13].data_data = 0x0f; 789 dcmintschm[brd] = 0; 790 } 791 while (dcm->dcm_cr & CR_TIMER) ; 792 SEM_LOCK(dcm); 793 dcm->dcm_cr |= CR_TIMER; /* toggle card 16.7ms interrupts */ 794 SEM_UNLOCK(dcm); 795 } 796 797 #ifdef notdef 798 /* 799 * Following are all routines needed for DCM to act as console 800 */ 801 802 struct tty * 803 dcmcninit(majordev) 804 dev_t majordev; 805 { 806 register struct dcmdevice *dcm; 807 int unit, s; 808 short stat; 809 810 unit = CONUNIT; /* XXX */ 811 dcm_addr[BOARD(CONUNIT)] = CONADDR; /* XXX */ 812 813 dcm = dcm_addr[unit]; 814 s = splhigh(); 815 /* do something */ 816 splx(s); 817 dcmconsole = unit; 818 if (majordev) 819 dcm_tty[unit].t_dev = makedev(majordev, unit); 820 return(&dcm_tty[unit]); 821 } 822 823 dcmcngetc(dev) 824 { 825 return(0); 826 } 827 828 /* 829 * Console kernel output character routine. 830 */ 831 dcmcnputc(dev, c) 832 dev_t dev; 833 register int c; 834 { 835 register struct dcmdevice *dcm = dcm_addr[BOARD(dev)]; 836 int port = PORT(dev); 837 short stat; 838 int head, tail, next; 839 int s = splhigh(); 840 841 if (dcmconsole == -1) 842 (void) dcmcninit(0); 843 844 do { 845 tail = dcm->dcm_ttail[port].ptr & TX_MASK; 846 head = dcm->dcm_thead[port].ptr & TX_MASK; 847 } while (tail != head); 848 next = (dcm->dcm_ttail[port].ptr + 1) & TX_MASK; 849 850 dcm->dcm_tfifos[3 - port][tail].data_char = c; 851 dcm->dcm_ttail[port].ptr = next; 852 853 dcm->dcm_cmdtab[port].dcm_data = CT_TX; 854 SEM_LOCK(dcm); 855 dcm->dcm_cr = (1 << port); 856 SEM_UNLOCK(dcm); 857 858 splx(s); 859 } 860 #endif 861 #endif 862