1 /* 2 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)dca.c 7.4 (Berkeley) 06/06/90 8 */ 9 10 #include "dca.h" 11 #if NDCA > 0 12 /* 13 * 98626/98644/internal serial interface 14 */ 15 #include "param.h" 16 #include "systm.h" 17 #include "ioctl.h" 18 #include "tty.h" 19 #include "user.h" 20 #include "conf.h" 21 #include "file.h" 22 #include "uio.h" 23 #include "kernel.h" 24 #include "syslog.h" 25 26 #include "device.h" 27 #include "dcareg.h" 28 #include "machine/cpu.h" 29 #include "machine/isr.h" 30 31 int dcaprobe(); 32 struct driver dcadriver = { 33 dcaprobe, "dca", 34 }; 35 36 int dcastart(), dcaparam(), dcaintr(); 37 int dcasoftCAR; 38 int dca_active; 39 int ndca = NDCA; 40 int dcaconsole = -1; 41 int dcadefaultrate = TTYDEF_SPEED; 42 struct dcadevice *dca_addr[NDCA]; 43 struct tty dca_tty[NDCA]; 44 struct isr dcaisr[NDCA]; 45 46 struct speedtab dcaspeedtab[] = { 47 0, 0, 48 50, DCABRD(50), 49 75, DCABRD(75), 50 110, DCABRD(110), 51 134, DCABRD(134), 52 150, DCABRD(150), 53 200, DCABRD(200), 54 300, DCABRD(300), 55 600, DCABRD(600), 56 1200, DCABRD(1200), 57 1800, DCABRD(1800), 58 2400, DCABRD(2400), 59 4800, DCABRD(4800), 60 9600, DCABRD(9600), 61 19200, DCABRD(19200), 62 38400, DCABRD(38400), 63 -1, -1 64 }; 65 66 extern struct tty *constty; 67 #ifdef KGDB 68 extern int kgdb_dev; 69 extern int kgdb_rate; 70 extern int kgdb_debug_init; 71 #endif 72 73 #define UNIT(x) minor(x) 74 75 dcaprobe(hd) 76 register struct hp_device *hd; 77 { 78 register struct dcadevice *dca; 79 register int unit; 80 81 dca = (struct dcadevice *)hd->hp_addr; 82 if (dca->dca_irid != DCAID0 && 83 dca->dca_irid != DCAREMID0 && 84 dca->dca_irid != DCAID1 && 85 dca->dca_irid != DCAREMID1) 86 return (0); 87 unit = hd->hp_unit; 88 if (unit == dcaconsole) 89 DELAY(100000); 90 dca->dca_irid = 0xFF; 91 DELAY(100); 92 93 hd->hp_ipl = DCAIPL(dca->dca_ic); 94 dcaisr[unit].isr_ipl = hd->hp_ipl; 95 dcaisr[unit].isr_arg = unit; 96 dcaisr[unit].isr_intr = dcaintr; 97 dca_addr[unit] = dca; 98 dca_active |= 1 << unit; 99 dcasoftCAR = hd->hp_flags; 100 isrlink(&dcaisr[unit]); 101 #ifdef KGDB 102 if (kgdb_dev == makedev(1, unit)) { 103 if (dcaconsole == unit) 104 kgdb_dev = -1; /* can't debug over console port */ 105 else { 106 (void) dcainit(unit); 107 dcaconsole = -2; /* XXX */ 108 if (kgdb_debug_init) { 109 printf("dca%d: kgdb waiting...", unit); 110 /* trap into kgdb */ 111 asm("trap #15;"); 112 printf("connected.\n"); 113 } else 114 printf("dca%d: kgdb enabled\n", unit); 115 } 116 } 117 #endif 118 dca->dca_ic = IC_IE; 119 /* 120 * Need to reset baud rate, etc. of next print so reset dcaconsole. 121 * Also make sure console is always "hardwired" 122 */ 123 if (unit == dcaconsole) { 124 dcaconsole = -1; 125 dcasoftCAR |= (1 << unit); 126 } 127 return (1); 128 } 129 130 dcaopen(dev, flag) 131 dev_t dev; 132 { 133 register struct tty *tp; 134 register int unit; 135 int error; 136 137 unit = UNIT(dev); 138 if (unit >= NDCA || (dca_active & (1 << unit)) == 0) 139 return (ENXIO); 140 tp = &dca_tty[unit]; 141 tp->t_oproc = dcastart; 142 tp->t_param = dcaparam; 143 tp->t_dev = dev; 144 if ((tp->t_state & TS_ISOPEN) == 0) { 145 tp->t_state |= TS_WOPEN; 146 ttychars(tp); 147 tp->t_iflag = TTYDEF_IFLAG; 148 tp->t_oflag = TTYDEF_OFLAG; 149 tp->t_cflag = TTYDEF_CFLAG; 150 tp->t_lflag = TTYDEF_LFLAG; 151 tp->t_ispeed = tp->t_ospeed = dcadefaultrate; 152 dcaparam(tp, &tp->t_termios); 153 ttsetwater(tp); 154 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 155 return (EBUSY); 156 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET); 157 if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD)) 158 tp->t_state |= TS_CARR_ON; 159 (void) spltty(); 160 while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) && 161 (tp->t_state & TS_CARR_ON) == 0) { 162 tp->t_state |= TS_WOPEN; 163 if ((error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 164 ttopen, 0)) || 165 (error = ttclosed(tp))) { 166 tp->t_state &= ~TS_WOPEN; 167 (void) spl0(); 168 return (error); 169 } 170 } 171 (void) spl0(); 172 return ((*linesw[tp->t_line].l_open)(dev, tp)); 173 } 174 175 /*ARGSUSED*/ 176 dcaclose(dev, flag) 177 dev_t dev; 178 { 179 register struct tty *tp; 180 register struct dcadevice *dca; 181 register int unit; 182 183 unit = UNIT(dev); 184 dca = dca_addr[unit]; 185 tp = &dca_tty[unit]; 186 (*linesw[tp->t_line].l_close)(tp); 187 dca->dca_cfcr &= ~CFCR_SBREAK; 188 #ifdef KGDB 189 /* do not disable interrupts if debugging */ 190 if (kgdb_dev != makedev(1, unit)) 191 #endif 192 dca->dca_ier = 0; 193 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 194 (tp->t_state&TS_ISOPEN) == 0) 195 (void) dcamctl(dev, 0, DMSET); 196 ttyclose(tp); 197 return(0); 198 } 199 200 dcaread(dev, uio, flag) 201 dev_t dev; 202 struct uio *uio; 203 { 204 register struct tty *tp = &dca_tty[UNIT(dev)]; 205 206 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 207 } 208 209 dcawrite(dev, uio, flag) 210 dev_t dev; 211 struct uio *uio; 212 { 213 int unit = UNIT(dev); 214 register struct tty *tp = &dca_tty[unit]; 215 216 /* 217 * (XXX) We disallow virtual consoles if the physical console is 218 * a serial port. This is in case there is a display attached that 219 * is not the console. In that situation we don't need/want the X 220 * server taking over the console. 221 */ 222 if (constty && unit == dcaconsole) 223 constty = NULL; 224 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 225 } 226 227 dcaintr(unit) 228 register int unit; 229 { 230 register struct dcadevice *dca; 231 register int code; 232 233 dca = dca_addr[unit]; 234 if ((dca->dca_ic & IC_IR) == 0) 235 return(0); 236 while (((code = dca->dca_iir) & IIR_NOPEND) == 0) { 237 code &= IIR_IMASK; 238 if (code == IIR_RLS) 239 dcaeint(unit, dca); 240 else if (code == IIR_RXRDY) 241 dcarint(unit, dca); 242 else if (code == IIR_TXRDY) 243 dcaxint(unit, dca); 244 else 245 dcamint(unit, dca); 246 } 247 return(1); 248 } 249 250 dcaeint(unit, dca) 251 register int unit; 252 register struct dcadevice *dca; 253 { 254 register struct tty *tp; 255 register int stat, c; 256 257 tp = &dca_tty[unit]; 258 stat = dca->dca_lsr; 259 c = dca->dca_data & 0xff; 260 if ((tp->t_state & TS_ISOPEN) == 0) { 261 #ifdef KGDB 262 /* we don't care about parity errors */ 263 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 264 kgdb_dev == makedev(1, unit) && c == '!') { 265 printf("kgdb trap from dca%d\n", unit); 266 /* trap into kgdb */ 267 asm("trap #15;"); 268 } 269 #endif 270 return; 271 } 272 if (stat & (LSR_BI | LSR_FE)) 273 c |= TTY_FE; 274 else if (stat & LSR_PE) 275 c |= TTY_PE; 276 else if (stat & LSR_OE) 277 log(LOG_WARNING, "dca%d: silo overflow\n", unit); 278 (*linesw[tp->t_line].l_rint)(c, tp); 279 } 280 281 dcarint(unit, dca) 282 int unit; 283 register struct dcadevice *dca; 284 { 285 register struct tty *tp; 286 register int c; 287 288 tp = &dca_tty[unit]; 289 c = dca->dca_data; 290 if ((tp->t_state & TS_ISOPEN) == 0) { 291 #ifdef KGDB 292 if (kgdb_dev == makedev(1, unit) && c == '!') { 293 printf("kgdb trap from dca%d\n", unit); 294 /* trap into kgdb */ 295 asm("trap #15;"); 296 } 297 #endif 298 return; 299 } 300 (*linesw[tp->t_line].l_rint)(c, tp); 301 } 302 303 /*ARGSUSED*/ 304 dcaxint(unit, dca) 305 int unit; 306 struct dcadevice *dca; 307 { 308 register struct tty *tp; 309 310 tp = &dca_tty[unit]; 311 tp->t_state &= ~TS_BUSY; 312 if (tp->t_state & TS_FLUSH) 313 tp->t_state &= ~TS_FLUSH; 314 if (tp->t_line) 315 (*linesw[tp->t_line].l_start)(tp); 316 else 317 dcastart(tp); 318 } 319 320 dcamint(unit, dca) 321 register int unit; 322 register struct dcadevice *dca; 323 { 324 register struct tty *tp; 325 register int stat; 326 327 tp = &dca_tty[unit]; 328 stat = dca->dca_msr; 329 if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) { 330 if (stat & MSR_DCD) 331 (void) (*linesw[tp->t_line].l_modem)(tp, 1); 332 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 333 dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); 334 } 335 } 336 337 dcaioctl(dev, cmd, data, flag) 338 dev_t dev; 339 caddr_t data; 340 { 341 register struct tty *tp; 342 register int unit = UNIT(dev); 343 register struct dcadevice *dca; 344 register int error; 345 346 tp = &dca_tty[unit]; 347 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 348 if (error >= 0) 349 return (error); 350 error = ttioctl(tp, cmd, data, flag); 351 if (error >= 0) 352 return (error); 353 354 dca = dca_addr[unit]; 355 switch (cmd) { 356 357 case TIOCSBRK: 358 dca->dca_cfcr |= CFCR_SBREAK; 359 break; 360 361 case TIOCCBRK: 362 dca->dca_cfcr &= ~CFCR_SBREAK; 363 break; 364 365 case TIOCSDTR: 366 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); 367 break; 368 369 case TIOCCDTR: 370 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); 371 break; 372 373 case TIOCMSET: 374 (void) dcamctl(dev, *(int *)data, DMSET); 375 break; 376 377 case TIOCMBIS: 378 (void) dcamctl(dev, *(int *)data, DMBIS); 379 break; 380 381 case TIOCMBIC: 382 (void) dcamctl(dev, *(int *)data, DMBIC); 383 break; 384 385 case TIOCMGET: 386 *(int *)data = dcamctl(dev, 0, DMGET); 387 break; 388 389 default: 390 return (ENOTTY); 391 } 392 return (0); 393 } 394 395 dcaparam(tp, t) 396 register struct tty *tp; 397 register struct termios *t; 398 { 399 register struct dcadevice *dca; 400 register int cfcr, cflag = t->c_cflag; 401 int unit = UNIT(tp->t_dev); 402 int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); 403 404 /* check requested parameters */ 405 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 406 return(EINVAL); 407 /* and copy to tty */ 408 tp->t_ispeed = t->c_ispeed; 409 tp->t_ospeed = t->c_ospeed; 410 tp->t_cflag = cflag; 411 412 dca = dca_addr[unit]; 413 dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; 414 if (ospeed == 0) { 415 (void) dcamctl(unit, 0, DMSET); /* hang up line */ 416 return(0); 417 } 418 dca->dca_cfcr |= CFCR_DLAB; 419 dca->dca_data = ospeed & 0xFF; 420 dca->dca_ier = ospeed >> 8; 421 switch (cflag&CSIZE) { 422 case CS5: 423 cfcr = CFCR_5BITS; break; 424 case CS6: 425 cfcr = CFCR_6BITS; break; 426 case CS7: 427 cfcr = CFCR_7BITS; break; 428 case CS8: 429 cfcr = CFCR_8BITS; break; 430 } 431 if (cflag&PARENB) { 432 cfcr |= CFCR_PENAB; 433 if ((cflag&PARODD) == 0) 434 cfcr |= CFCR_PEVEN; 435 } 436 if (cflag&CSTOPB) 437 cfcr |= CFCR_STOPB; 438 dca->dca_cfcr = cfcr; 439 return(0); 440 } 441 442 dcastart(tp) 443 register struct tty *tp; 444 { 445 register struct dcadevice *dca; 446 int s, unit, c; 447 448 unit = UNIT(tp->t_dev); 449 dca = dca_addr[unit]; 450 s = spltty(); 451 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 452 goto out; 453 if (tp->t_outq.c_cc <= tp->t_lowat) { 454 if (tp->t_state&TS_ASLEEP) { 455 tp->t_state &= ~TS_ASLEEP; 456 wakeup((caddr_t)&tp->t_outq); 457 } 458 if (tp->t_wsel) { 459 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 460 tp->t_wsel = 0; 461 tp->t_state &= ~TS_WCOLL; 462 } 463 } 464 if (tp->t_outq.c_cc == 0) 465 goto out; 466 c = getc(&tp->t_outq); 467 tp->t_state |= TS_BUSY; 468 dca->dca_data = c; 469 out: 470 splx(s); 471 } 472 473 /* 474 * Stop output on a line. 475 */ 476 /*ARGSUSED*/ 477 dcastop(tp, flag) 478 register struct tty *tp; 479 { 480 register int s; 481 482 s = spltty(); 483 if (tp->t_state & TS_BUSY) { 484 if ((tp->t_state&TS_TTSTOP)==0) 485 tp->t_state |= TS_FLUSH; 486 } 487 splx(s); 488 } 489 490 dcamctl(dev, bits, how) 491 dev_t dev; 492 int bits, how; 493 { 494 register struct dcadevice *dca; 495 register int unit; 496 int s; 497 498 unit = UNIT(dev); 499 dca = dca_addr[unit]; 500 s = spltty(); 501 switch (how) { 502 503 case DMSET: 504 dca->dca_mcr = bits; 505 break; 506 507 case DMBIS: 508 dca->dca_mcr |= bits; 509 break; 510 511 case DMBIC: 512 dca->dca_mcr &= ~bits; 513 break; 514 515 case DMGET: 516 bits = dca->dca_msr; 517 break; 518 } 519 (void) splx(s); 520 return(bits); 521 } 522 523 /* 524 * Following are all routines needed for DCA to act as console 525 */ 526 #include "machine/cons.h" 527 528 dcacnprobe(cp) 529 struct consdev *cp; 530 { 531 int unit, i; 532 extern int dcaopen(); 533 534 /* XXX: ick */ 535 unit = CONUNIT; 536 dca_addr[CONUNIT] = CONADDR; 537 538 /* make sure hardware exists */ 539 if (badaddr((short *)dca_addr[unit])) { 540 cp->cn_pri = CN_DEAD; 541 return; 542 } 543 544 /* locate the major number */ 545 for (i = 0; i < nchrdev; i++) 546 if (cdevsw[i].d_open == dcaopen) 547 break; 548 549 /* initialize required fields */ 550 cp->cn_dev = makedev(i, unit); 551 cp->cn_tp = &dca_tty[unit]; 552 switch (dca_addr[unit]->dca_irid) { 553 case DCAID0: 554 case DCAID1: 555 cp->cn_pri = CN_NORMAL; 556 break; 557 case DCAREMID0: 558 case DCAREMID1: 559 cp->cn_pri = CN_REMOTE; 560 break; 561 default: 562 cp->cn_pri = CN_DEAD; 563 break; 564 } 565 } 566 567 dcacninit(cp) 568 struct consdev *cp; 569 { 570 int unit = UNIT(cp->cn_dev); 571 572 dcainit(unit); 573 dcaconsole = unit; 574 } 575 576 dcainit(unit) 577 int unit; 578 { 579 register struct dcadevice *dca; 580 int s, rate; 581 short stat; 582 583 #ifdef lint 584 stat = unit; if (stat) return; 585 #endif 586 dca = dca_addr[unit]; 587 s = splhigh(); 588 dca->dca_irid = 0xFF; 589 DELAY(100); 590 dca->dca_ic = IC_IE; 591 dca->dca_cfcr = CFCR_DLAB; 592 rate = ttspeedtab(dcadefaultrate, dcaspeedtab); 593 dca->dca_data = rate & 0xFF; 594 dca->dca_ier = rate >> 8; 595 dca->dca_cfcr = CFCR_8BITS; 596 dca->dca_ier = IER_ERXRDY | IER_ETXRDY; 597 stat = dca->dca_iir; 598 splx(s); 599 } 600 601 dcacngetc(dev) 602 { 603 register struct dcadevice *dca = dca_addr[UNIT(dev)]; 604 short stat; 605 int c, s; 606 607 #ifdef lint 608 stat = dev; if (stat) return(0); 609 #endif 610 s = splhigh(); 611 while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) 612 ; 613 c = dca->dca_data; 614 stat = dca->dca_iir; 615 splx(s); 616 return(c); 617 } 618 619 /* 620 * Console kernel output character routine. 621 */ 622 dcacnputc(dev, c) 623 dev_t dev; 624 register int c; 625 { 626 register struct dcadevice *dca = dca_addr[UNIT(dev)]; 627 register int timo; 628 short stat; 629 int s = splhigh(); 630 631 #ifdef lint 632 stat = dev; if (stat) return; 633 #endif 634 if (dcaconsole == -1) { 635 (void) dcainit(UNIT(dev)); 636 dcaconsole = UNIT(dev); 637 } 638 /* wait for any pending transmission to finish */ 639 timo = 50000; 640 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 641 ; 642 dca->dca_data = c; 643 /* wait for this transmission to complete */ 644 timo = 1500000; 645 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 646 ; 647 /* clear any interrupts generated by this transmission */ 648 stat = dca->dca_iir; 649 splx(s); 650 } 651 #endif 652