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.2 (Berkeley) 05/25/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 ttychars(tp); 146 tp->t_iflag = TTYDEF_IFLAG; 147 tp->t_oflag = TTYDEF_OFLAG; 148 tp->t_cflag = TTYDEF_CFLAG; 149 tp->t_lflag = TTYDEF_LFLAG; 150 tp->t_ispeed = tp->t_ospeed = dcadefaultrate; 151 dcaparam(tp, &tp->t_termios); 152 ttsetwater(tp); 153 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) 154 return (EBUSY); 155 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET); 156 if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD)) 157 tp->t_state |= TS_CARR_ON; 158 (void) spltty(); 159 while (!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) && 160 (tp->t_state & TS_CARR_ON) == 0) { 161 tp->t_state |= TS_WOPEN; 162 if (error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 163 ttopen, 0)) { 164 tp->t_state &= ~TS_WOPEN; 165 (void) spl0(); 166 return (error); 167 } 168 } 169 (void) spl0(); 170 return ((*linesw[tp->t_line].l_open)(dev, tp)); 171 } 172 173 /*ARGSUSED*/ 174 dcaclose(dev, flag) 175 dev_t dev; 176 { 177 register struct tty *tp; 178 register struct dcadevice *dca; 179 register int unit; 180 181 unit = UNIT(dev); 182 dca = dca_addr[unit]; 183 tp = &dca_tty[unit]; 184 (*linesw[tp->t_line].l_close)(tp); 185 dca->dca_cfcr &= ~CFCR_SBREAK; 186 #ifdef KGDB 187 /* do not disable interrupts if debugging */ 188 if (kgdb_dev != makedev(1, unit)) 189 #endif 190 dca->dca_ier = 0; 191 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 192 (tp->t_state&TS_ISOPEN) == 0) 193 (void) dcamctl(dev, 0, DMSET); 194 ttyclose(tp); 195 return(0); 196 } 197 198 dcaread(dev, uio, flag) 199 dev_t dev; 200 struct uio *uio; 201 { 202 register struct tty *tp = &dca_tty[UNIT(dev)]; 203 204 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 205 } 206 207 dcawrite(dev, uio, flag) 208 dev_t dev; 209 struct uio *uio; 210 { 211 int unit = UNIT(dev); 212 register struct tty *tp = &dca_tty[unit]; 213 214 /* 215 * (XXX) We disallow virtual consoles if the physical console is 216 * a serial port. This is in case there is a display attached that 217 * is not the console. In that situation we don't need/want the X 218 * server taking over the console. 219 */ 220 if (constty && unit == dcaconsole) 221 constty = NULL; 222 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 223 } 224 225 dcaintr(unit) 226 register int unit; 227 { 228 register struct dcadevice *dca; 229 register int code; 230 231 dca = dca_addr[unit]; 232 if ((dca->dca_ic & IC_IR) == 0) 233 return(0); 234 while (((code = dca->dca_iir) & IIR_NOPEND) == 0) { 235 code &= IIR_IMASK; 236 if (code == IIR_RLS) 237 dcaeint(unit, dca); 238 else if (code == IIR_RXRDY) 239 dcarint(unit, dca); 240 else if (code == IIR_TXRDY) 241 dcaxint(unit, dca); 242 else 243 dcamint(unit, dca); 244 } 245 return(1); 246 } 247 248 dcaeint(unit, dca) 249 register int unit; 250 register struct dcadevice *dca; 251 { 252 register struct tty *tp; 253 register int stat, c; 254 255 tp = &dca_tty[unit]; 256 stat = dca->dca_lsr; 257 c = dca->dca_data & 0xff; 258 if ((tp->t_state & TS_ISOPEN) == 0) { 259 #ifdef KGDB 260 /* we don't care about parity errors */ 261 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 262 kgdb_dev == makedev(1, unit) && c == '!') { 263 printf("kgdb trap from dca%d\n", unit); 264 /* trap into kgdb */ 265 asm("trap #15;"); 266 } 267 #endif 268 return; 269 } 270 if (stat & (LSR_BI | LSR_FE)) 271 c |= TTY_FE; 272 else if (stat & LSR_PE) 273 c |= TTY_PE; 274 else if (stat & LSR_OE) 275 log(LOG_WARNING, "dca%d: silo overflow\n", unit); 276 (*linesw[tp->t_line].l_rint)(c, tp); 277 } 278 279 dcarint(unit, dca) 280 int unit; 281 register struct dcadevice *dca; 282 { 283 register struct tty *tp; 284 register int c; 285 286 tp = &dca_tty[unit]; 287 c = dca->dca_data; 288 if ((tp->t_state & TS_ISOPEN) == 0) { 289 #ifdef KGDB 290 if (kgdb_dev == makedev(1, unit) && c == '!') { 291 printf("kgdb trap from dca%d\n", unit); 292 /* trap into kgdb */ 293 asm("trap #15;"); 294 } 295 #endif 296 return; 297 } 298 (*linesw[tp->t_line].l_rint)(c, tp); 299 } 300 301 /*ARGSUSED*/ 302 dcaxint(unit, dca) 303 int unit; 304 struct dcadevice *dca; 305 { 306 register struct tty *tp; 307 308 tp = &dca_tty[unit]; 309 tp->t_state &= ~TS_BUSY; 310 if (tp->t_state & TS_FLUSH) 311 tp->t_state &= ~TS_FLUSH; 312 if (tp->t_line) 313 (*linesw[tp->t_line].l_start)(tp); 314 else 315 dcastart(tp); 316 } 317 318 dcamint(unit, dca) 319 register int unit; 320 register struct dcadevice *dca; 321 { 322 register struct tty *tp; 323 register int stat; 324 325 tp = &dca_tty[unit]; 326 stat = dca->dca_msr; 327 if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) { 328 if (stat & MSR_DCD) 329 (void) (*linesw[tp->t_line].l_modem)(tp, 1); 330 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 331 dca->dca_mcr &= ~(MCR_DTR | MCR_RTS); 332 } 333 } 334 335 dcaioctl(dev, cmd, data, flag) 336 dev_t dev; 337 caddr_t data; 338 { 339 register struct tty *tp; 340 register int unit = UNIT(dev); 341 register struct dcadevice *dca; 342 register int error; 343 344 tp = &dca_tty[unit]; 345 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 346 if (error >= 0) 347 return (error); 348 error = ttioctl(tp, cmd, data, flag); 349 if (error >= 0) 350 return (error); 351 352 dca = dca_addr[unit]; 353 switch (cmd) { 354 355 case TIOCSBRK: 356 dca->dca_cfcr |= CFCR_SBREAK; 357 break; 358 359 case TIOCCBRK: 360 dca->dca_cfcr &= ~CFCR_SBREAK; 361 break; 362 363 case TIOCSDTR: 364 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS); 365 break; 366 367 case TIOCCDTR: 368 (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC); 369 break; 370 371 case TIOCMSET: 372 (void) dcamctl(dev, *(int *)data, DMSET); 373 break; 374 375 case TIOCMBIS: 376 (void) dcamctl(dev, *(int *)data, DMBIS); 377 break; 378 379 case TIOCMBIC: 380 (void) dcamctl(dev, *(int *)data, DMBIC); 381 break; 382 383 case TIOCMGET: 384 *(int *)data = dcamctl(dev, 0, DMGET); 385 break; 386 387 default: 388 return (ENOTTY); 389 } 390 return (0); 391 } 392 393 dcaparam(tp, t) 394 register struct tty *tp; 395 register struct termios *t; 396 { 397 register struct dcadevice *dca; 398 register int cfcr, cflag = t->c_cflag; 399 int unit = UNIT(tp->t_dev); 400 int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab); 401 402 /* check requested parameters */ 403 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 404 return(EINVAL); 405 /* and copy to tty */ 406 tp->t_ispeed = t->c_ispeed; 407 tp->t_ospeed = t->c_ospeed; 408 tp->t_cflag = cflag; 409 410 dca = dca_addr[unit]; 411 dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC; 412 if (ospeed == 0) { 413 (void) dcamctl(unit, 0, DMSET); /* hang up line */ 414 return(0); 415 } 416 dca->dca_cfcr |= CFCR_DLAB; 417 dca->dca_data = ospeed & 0xFF; 418 dca->dca_ier = ospeed >> 8; 419 switch (cflag&CSIZE) { 420 case CS5: 421 cfcr = CFCR_5BITS; break; 422 case CS6: 423 cfcr = CFCR_6BITS; break; 424 case CS7: 425 cfcr = CFCR_7BITS; break; 426 case CS8: 427 cfcr = CFCR_8BITS; break; 428 } 429 if (cflag&PARENB) { 430 cfcr |= CFCR_PENAB; 431 if ((cflag&PARODD) == 0) 432 cfcr |= CFCR_PEVEN; 433 } 434 if (cflag&CSTOPB) 435 cfcr |= CFCR_STOPB; 436 dca->dca_cfcr = cfcr; 437 return(0); 438 } 439 440 dcastart(tp) 441 register struct tty *tp; 442 { 443 register struct dcadevice *dca; 444 int s, unit, c; 445 446 unit = UNIT(tp->t_dev); 447 dca = dca_addr[unit]; 448 s = spltty(); 449 if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) 450 goto out; 451 if (tp->t_outq.c_cc <= tp->t_lowat) { 452 if (tp->t_state&TS_ASLEEP) { 453 tp->t_state &= ~TS_ASLEEP; 454 wakeup((caddr_t)&tp->t_outq); 455 } 456 if (tp->t_wsel) { 457 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 458 tp->t_wsel = 0; 459 tp->t_state &= ~TS_WCOLL; 460 } 461 } 462 if (tp->t_outq.c_cc == 0) 463 goto out; 464 c = getc(&tp->t_outq); 465 tp->t_state |= TS_BUSY; 466 dca->dca_data = c; 467 out: 468 splx(s); 469 } 470 471 /* 472 * Stop output on a line. 473 */ 474 /*ARGSUSED*/ 475 dcastop(tp, flag) 476 register struct tty *tp; 477 { 478 register int s; 479 480 s = spltty(); 481 if (tp->t_state & TS_BUSY) { 482 if ((tp->t_state&TS_TTSTOP)==0) 483 tp->t_state |= TS_FLUSH; 484 } 485 splx(s); 486 } 487 488 dcamctl(dev, bits, how) 489 dev_t dev; 490 int bits, how; 491 { 492 register struct dcadevice *dca; 493 register int unit; 494 int s; 495 496 unit = UNIT(dev); 497 dca = dca_addr[unit]; 498 s = spltty(); 499 switch (how) { 500 501 case DMSET: 502 dca->dca_mcr = bits; 503 break; 504 505 case DMBIS: 506 dca->dca_mcr |= bits; 507 break; 508 509 case DMBIC: 510 dca->dca_mcr &= ~bits; 511 break; 512 513 case DMGET: 514 bits = dca->dca_msr; 515 break; 516 } 517 (void) splx(s); 518 return(bits); 519 } 520 521 /* 522 * Following are all routines needed for DCA to act as console 523 */ 524 #include "machine/cons.h" 525 526 dcacnprobe(cp) 527 struct consdev *cp; 528 { 529 int unit, i; 530 extern int dcaopen(); 531 532 /* XXX: ick */ 533 unit = CONUNIT; 534 dca_addr[CONUNIT] = CONADDR; 535 536 /* make sure hardware exists */ 537 if (badaddr((short *)dca_addr[unit])) { 538 cp->cn_pri = CN_DEAD; 539 return; 540 } 541 542 /* locate the major number */ 543 for (i = 0; i < nchrdev; i++) 544 if (cdevsw[i].d_open == dcaopen) 545 break; 546 547 /* initialize required fields */ 548 cp->cn_dev = makedev(i, unit); 549 cp->cn_tp = &dca_tty[unit]; 550 switch (dca_addr[unit]->dca_irid) { 551 case DCAID0: 552 case DCAID1: 553 cp->cn_pri = CN_NORMAL; 554 break; 555 case DCAREMID0: 556 case DCAREMID1: 557 cp->cn_pri = CN_REMOTE; 558 break; 559 default: 560 cp->cn_pri = CN_DEAD; 561 break; 562 } 563 } 564 565 dcacninit(cp) 566 struct consdev *cp; 567 { 568 int unit = UNIT(cp->cn_dev); 569 570 dcainit(unit); 571 dcaconsole = unit; 572 } 573 574 dcainit(unit) 575 int unit; 576 { 577 register struct dcadevice *dca; 578 int s, rate; 579 short stat; 580 581 #ifdef lint 582 stat = unit; if (stat) return; 583 #endif 584 dca = dca_addr[unit]; 585 s = splhigh(); 586 dca->dca_irid = 0xFF; 587 DELAY(100); 588 dca->dca_ic = IC_IE; 589 dca->dca_cfcr = CFCR_DLAB; 590 rate = ttspeedtab(dcadefaultrate, dcaspeedtab); 591 dca->dca_data = rate & 0xFF; 592 dca->dca_ier = rate >> 8; 593 dca->dca_cfcr = CFCR_8BITS; 594 dca->dca_ier = IER_ERXRDY | IER_ETXRDY; 595 stat = dca->dca_iir; 596 splx(s); 597 } 598 599 dcacngetc(dev) 600 { 601 register struct dcadevice *dca = dca_addr[UNIT(dev)]; 602 short stat; 603 int c, s; 604 605 #ifdef lint 606 stat = dev; if (stat) return(0); 607 #endif 608 s = splhigh(); 609 while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0) 610 ; 611 c = dca->dca_data; 612 stat = dca->dca_iir; 613 splx(s); 614 return(c); 615 } 616 617 /* 618 * Console kernel output character routine. 619 */ 620 dcacnputc(dev, c) 621 dev_t dev; 622 register int c; 623 { 624 register struct dcadevice *dca = dca_addr[UNIT(dev)]; 625 register int timo; 626 short stat; 627 int s = splhigh(); 628 629 #ifdef lint 630 stat = dev; if (stat) return; 631 #endif 632 if (dcaconsole == -1) { 633 (void) dcainit(UNIT(dev)); 634 dcaconsole = UNIT(dev); 635 } 636 /* wait for any pending transmission to finish */ 637 timo = 50000; 638 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 639 ; 640 dca->dca_data = c; 641 /* wait for this transmission to complete */ 642 timo = 1500000; 643 while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo) 644 ; 645 /* clear any interrupts generated by this transmission */ 646 stat = dca->dca_iir; 647 splx(s); 648 } 649 #endif 650