1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)com.c 7.9 (Berkeley) 10/11/92 8 */ 9 10 #include "com.h" 11 #if NCOM > 0 12 /* 13 * COM driver, based on HP dca driver 14 * uses National Semiconductor NS16450/NS16550AF UART 15 */ 16 #include <sys/param.h> 17 #include <sys/systm.h> 18 #include <sys/ioctl.h> 19 #include <sys/tty.h> 20 #include <sys/proc.h> 21 #include <sys/user.h> 22 #include <sys/conf.h> 23 #include <sys/file.h> 24 #include <sys/uio.h> 25 #include <sys/kernel.h> 26 #include <sys/syslog.h> 27 28 #include <i386/isa/isa_device.h> 29 #include <i386/isa/comreg.h> 30 #include <i386/isa/ic/ns16550.h> 31 32 void comstart(); 33 int comprobe(), comattach(), comintr(), comparam(); 34 35 struct isa_driver comdriver = { 36 comprobe, comattach, "com" 37 }; 38 39 int comsoftCAR; 40 int com_active; 41 int com_hasfifo; 42 int ncom = NCOM; 43 #ifdef COMCONSOLE 44 int comconsole = COMCONSOLE; 45 #else 46 int comconsole = -1; 47 #endif 48 int comconsinit; 49 int comdefaultrate = TTYDEF_SPEED; 50 int commajor; 51 short com_addr[NCOM]; 52 struct tty com_tty[NCOM]; 53 54 struct speedtab comspeedtab[] = { 55 0, 0, 56 50, COMBRD(50), 57 75, COMBRD(75), 58 110, COMBRD(110), 59 134, COMBRD(134), 60 150, COMBRD(150), 61 200, COMBRD(200), 62 300, COMBRD(300), 63 600, COMBRD(600), 64 1200, COMBRD(1200), 65 1800, COMBRD(1800), 66 2400, COMBRD(2400), 67 4800, COMBRD(4800), 68 9600, COMBRD(9600), 69 19200, COMBRD(19200), 70 38400, COMBRD(38400), 71 57600, COMBRD(57600), 72 -1, -1 73 }; 74 75 extern struct tty *constty; 76 #ifdef KGDB 77 #include <machine/remote-sl.h> 78 79 extern int kgdb_dev; 80 extern int kgdb_rate; 81 extern int kgdb_debug_init; 82 #endif 83 84 #define UNIT(x) minor(x) 85 86 comprobe(dev) 87 struct isa_device *dev; 88 { 89 /* force access to id reg */ 90 outb(dev->id_iobase+com_cfcr, inb (dev->id_iobase+com_cfcr) & ~0x80); 91 outb(dev->id_iobase+com_iir, 0); 92 if ((inb(dev->id_iobase+com_iir) & 0x38) == 0) 93 return(1); 94 return(1); 95 96 } 97 98 99 int 100 comattach(isdp) 101 struct isa_device *isdp; 102 { 103 struct tty *tp; 104 u_char unit; 105 int port = isdp->id_iobase; 106 107 unit = isdp->id_unit; 108 if (unit == comconsole) 109 DELAY(100000); 110 com_addr[unit] = port; 111 com_active |= 1 << unit; 112 comsoftCAR |= 1 << unit; /* XXX */ 113 114 /* look for a NS 16550AF UART with FIFOs */ 115 outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 116 DELAY(100); 117 if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) 118 com_hasfifo |= 1 << unit; 119 120 outb(port+com_ier, 0); 121 outb(port+com_mcr, 0 | MCR_IENABLE); 122 #ifdef KGDB 123 if (kgdb_dev == makedev(commajor, unit)) { 124 if (comconsole == unit) 125 kgdb_dev = -1; /* can't debug over console port */ 126 else { 127 (void) cominit(unit, kgdb_rate); 128 if (kgdb_debug_init) { 129 /* 130 * Print prefix of device name, 131 * let kgdb_connect print the rest. 132 */ 133 printf("com%d: ", unit); 134 kgdb_connect(1); 135 } else 136 printf("com%d: kgdb enabled\n", unit); 137 } 138 } 139 #endif 140 /* 141 * Need to reset baud rate, etc. of next print so reset comconsinit. 142 * Also make sure console is always "hardwired" 143 */ 144 if (unit == comconsole) { 145 comconsinit = 0; 146 comsoftCAR |= (1 << unit); 147 } 148 return (1); 149 } 150 151 /* ARGSUSED */ 152 #ifdef __STDC__ 153 comopen(dev_t dev, int flag, int mode, struct proc *p) 154 #else 155 comopen(dev, flag, mode, p) 156 dev_t dev; 157 int flag, mode; 158 struct proc *p; 159 #endif 160 { 161 register struct tty *tp; 162 register int unit; 163 int error = 0; 164 165 unit = UNIT(dev); 166 if (unit >= NCOM || (com_active & (1 << unit)) == 0) 167 return (ENXIO); 168 tp = &com_tty[unit]; 169 tp->t_oproc = comstart; 170 tp->t_param = comparam; 171 tp->t_dev = dev; 172 if ((tp->t_state & TS_ISOPEN) == 0) { 173 tp->t_state |= TS_WOPEN; 174 ttychars(tp); 175 if (tp->t_ispeed == 0) { 176 tp->t_iflag = TTYDEF_IFLAG; 177 tp->t_oflag = TTYDEF_OFLAG; 178 tp->t_cflag = TTYDEF_CFLAG; 179 tp->t_lflag = TTYDEF_LFLAG; 180 tp->t_ispeed = tp->t_ospeed = comdefaultrate; 181 } 182 comparam(tp, &tp->t_termios); 183 ttsetwater(tp); 184 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 185 return (EBUSY); 186 (void) spltty(); 187 (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET); 188 if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD)) 189 tp->t_state |= TS_CARR_ON; 190 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 191 (tp->t_state & TS_CARR_ON) == 0) { 192 tp->t_state |= TS_WOPEN; 193 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 194 ttopen, 0)) 195 break; 196 } 197 (void) spl0(); 198 if (error == 0) 199 error = (*linesw[tp->t_line].l_open)(dev, tp); 200 return (error); 201 } 202 203 /*ARGSUSED*/ 204 comclose(dev, flag, mode, p) 205 dev_t dev; 206 int flag, mode; 207 struct proc *p; 208 { 209 register struct tty *tp; 210 register com; 211 register int unit; 212 213 unit = UNIT(dev); 214 com = com_addr[unit]; 215 tp = &com_tty[unit]; 216 (*linesw[tp->t_line].l_close)(tp, flag); 217 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 218 #ifdef KGDB 219 /* do not disable interrupts if debugging */ 220 if (kgdb_dev != makedev(commajor, unit)) 221 #endif 222 outb(com+com_ier, 0); 223 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 224 (tp->t_state&TS_ISOPEN) == 0) 225 (void) commctl(dev, 0, DMSET); 226 ttyclose(tp); 227 return(0); 228 } 229 230 comread(dev, uio, flag) 231 dev_t dev; 232 struct uio *uio; 233 { 234 register struct tty *tp = &com_tty[UNIT(dev)]; 235 236 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 237 } 238 239 comwrite(dev, uio, flag) 240 dev_t dev; 241 struct uio *uio; 242 { 243 int unit = UNIT(dev); 244 register struct tty *tp = &com_tty[unit]; 245 246 /* 247 * (XXX) We disallow virtual consoles if the physical console is 248 * a serial port. This is in case there is a display attached that 249 * is not the console. In that situation we don't need/want the X 250 * server taking over the console. 251 */ 252 if (constty && unit == comconsole) 253 constty = NULL; 254 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 255 } 256 257 comintr(unit) 258 register int unit; 259 { 260 register com; 261 register u_char code; 262 register struct tty *tp; 263 264 com = com_addr[unit]; 265 while (1) { 266 code = inb(com+com_iir); 267 switch (code & IIR_IMASK) { 268 case IIR_NOPEND: 269 return (1); 270 case IIR_RXTOUT: 271 case IIR_RXRDY: 272 tp = &com_tty[unit]; 273 /* 274 * Process received bytes. Inline for speed... 275 */ 276 #ifdef KGDB 277 #define RCVBYTE() \ 278 code = inb(com+com_data); \ 279 if ((tp->t_state & TS_ISOPEN) == 0) { \ 280 if (kgdb_dev == makedev(commajor, unit) && \ 281 code == FRAME_END) \ 282 kgdb_connect(0); /* trap into kgdb */ \ 283 } else \ 284 (*linesw[tp->t_line].l_rint)(code, tp) 285 #else 286 #define RCVBYTE() \ 287 code = inb(com+com_data); \ 288 if (tp->t_state & TS_ISOPEN) \ 289 (*linesw[tp->t_line].l_rint)(code, tp) 290 #endif 291 292 RCVBYTE(); 293 294 if (com_hasfifo & (1 << unit)) 295 while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { 296 if (code == LSR_RXRDY) { 297 RCVBYTE(); 298 } else 299 comeint(unit, code, com); 300 } 301 break; 302 case IIR_TXRDY: 303 tp = &com_tty[unit]; 304 tp->t_state &=~ (TS_BUSY|TS_FLUSH); 305 if (tp->t_line) 306 (*linesw[tp->t_line].l_start)(tp); 307 else 308 comstart(tp); 309 break; 310 case IIR_RLS: 311 comeint(unit, inb(com+com_lsr), com); 312 break; 313 default: 314 if (code & IIR_NOPEND) 315 return (1); 316 log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", 317 unit, code); 318 /* fall through */ 319 case IIR_MLSC: 320 commint(unit, com); 321 break; 322 } 323 } 324 } 325 326 comeint(unit, stat, com) 327 register int unit, stat; 328 register com; 329 { 330 register struct tty *tp; 331 register int c; 332 333 tp = &com_tty[unit]; 334 c = inb(com+com_data); 335 if ((tp->t_state & TS_ISOPEN) == 0) { 336 #ifdef KGDB 337 /* we don't care about parity errors */ 338 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 339 kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 340 kgdb_connect(0); /* trap into kgdb */ 341 #endif 342 return; 343 } 344 if (stat & (LSR_BI | LSR_FE)) 345 c |= TTY_FE; 346 else if (stat & LSR_PE) 347 c |= TTY_PE; 348 else if (stat & LSR_OE) 349 log(LOG_WARNING, "com%d: silo overflow\n", unit); 350 (*linesw[tp->t_line].l_rint)(c, tp); 351 } 352 353 commint(unit, com) 354 register int unit; 355 register com; 356 { 357 register struct tty *tp; 358 register int stat; 359 360 tp = &com_tty[unit]; 361 stat = inb(com+com_msr); 362 if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) { 363 if (stat & MSR_DCD) 364 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 365 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 366 outb(com+com_mcr, 367 inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE); 368 } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 369 (tp->t_flags & CRTSCTS)) { 370 /* the line is up and we want to do rts/cts flow control */ 371 if (stat & MSR_CTS) { 372 tp->t_state &=~ TS_TTSTOP; 373 ttstart(tp); 374 } else 375 tp->t_state |= TS_TTSTOP; 376 } 377 } 378 379 comioctl(dev, cmd, data, flag, p) 380 dev_t dev; 381 int cmd, flag; 382 caddr_t data; 383 struct proc *p; 384 { 385 register struct tty *tp; 386 register int unit = UNIT(dev); 387 register com; 388 register int error; 389 390 tp = &com_tty[unit]; 391 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 392 if (error >= 0) 393 return (error); 394 error = ttioctl(tp, cmd, data, flag); 395 if (error >= 0) 396 return (error); 397 398 com = com_addr[unit]; 399 switch (cmd) { 400 401 case TIOCSBRK: 402 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK); 403 break; 404 405 case TIOCCBRK: 406 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 407 break; 408 409 case TIOCSDTR: 410 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS); 411 break; 412 413 case TIOCCDTR: 414 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC); 415 break; 416 417 case TIOCMSET: 418 (void) commctl(dev, *(int *)data, DMSET); 419 break; 420 421 case TIOCMBIS: 422 (void) commctl(dev, *(int *)data, DMBIS); 423 break; 424 425 case TIOCMBIC: 426 (void) commctl(dev, *(int *)data, DMBIC); 427 break; 428 429 case TIOCMGET: 430 *(int *)data = commctl(dev, 0, DMGET); 431 break; 432 433 default: 434 return (ENOTTY); 435 } 436 return (0); 437 } 438 439 comparam(tp, t) 440 register struct tty *tp; 441 register struct termios *t; 442 { 443 register com; 444 register int cfcr, cflag = t->c_cflag; 445 int unit = UNIT(tp->t_dev); 446 int ospeed = ttspeedtab(t->c_ospeed, comspeedtab); 447 448 /* check requested parameters */ 449 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 450 return(EINVAL); 451 /* and copy to tty */ 452 tp->t_ispeed = t->c_ispeed; 453 tp->t_ospeed = t->c_ospeed; 454 tp->t_cflag = cflag; 455 456 com = com_addr[unit]; 457 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/); 458 if (ospeed == 0) { 459 (void) commctl(unit, 0, DMSET); /* hang up line */ 460 return(0); 461 } 462 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB); 463 outb(com+com_data, ospeed & 0xFF); 464 outb(com+com_ier, ospeed >> 8); 465 switch (cflag&CSIZE) { 466 case CS5: 467 cfcr = CFCR_5BITS; break; 468 case CS6: 469 cfcr = CFCR_6BITS; break; 470 case CS7: 471 cfcr = CFCR_7BITS; break; 472 case CS8: 473 cfcr = CFCR_8BITS; break; 474 } 475 if (cflag&PARENB) { 476 cfcr |= CFCR_PENAB; 477 if ((cflag&PARODD) == 0) 478 cfcr |= CFCR_PEVEN; 479 } 480 if (cflag&CSTOPB) 481 cfcr |= CFCR_STOPB; 482 outb(com+com_cfcr, cfcr); 483 484 if (com_hasfifo & (1 << unit)) 485 outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); 486 487 return(0); 488 } 489 490 void 491 comstart(tp) 492 register struct tty *tp; 493 { 494 register com; 495 int s, unit, c; 496 497 unit = UNIT(tp->t_dev); 498 com = com_addr[unit]; 499 s = spltty(); 500 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 501 goto out; 502 if (tp->t_outq.c_cc <= tp->t_lowat) { 503 if (tp->t_state&TS_ASLEEP) { 504 tp->t_state &= ~TS_ASLEEP; 505 wakeup((caddr_t)&tp->t_outq); 506 } 507 selwakeup(&tp->t_wsel); 508 } 509 if (tp->t_outq.c_cc == 0) 510 goto out; 511 if (inb(com+com_lsr) & LSR_TXRDY) { 512 c = getc(&tp->t_outq); 513 tp->t_state |= TS_BUSY; 514 outb(com+com_data, c); 515 if (com_hasfifo & (1 << unit)) 516 for (c = 1; c < 16 && tp->t_outq.c_cc; ++c) 517 outb(com+com_data, getc(&tp->t_outq)); 518 } 519 out: 520 splx(s); 521 } 522 523 /* 524 * Stop output on a line. 525 */ 526 /*ARGSUSED*/ 527 comstop(tp, flag) 528 register struct tty *tp; 529 { 530 register int s; 531 532 s = spltty(); 533 if (tp->t_state & TS_BUSY) { 534 if ((tp->t_state&TS_TTSTOP)==0) 535 tp->t_state |= TS_FLUSH; 536 } 537 splx(s); 538 } 539 540 commctl(dev, bits, how) 541 dev_t dev; 542 int bits, how; 543 { 544 register com; 545 register int unit; 546 int s; 547 548 unit = UNIT(dev); 549 com = com_addr[unit]; 550 s = spltty(); 551 switch (how) { 552 553 case DMSET: 554 outb(com+com_mcr, bits | MCR_IENABLE); 555 break; 556 557 case DMBIS: 558 outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE); 559 break; 560 561 case DMBIC: 562 outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE); 563 break; 564 565 case DMGET: 566 bits = inb(com+com_msr); 567 break; 568 } 569 (void) splx(s); 570 return(bits); 571 } 572 573 /* 574 * Following are all routines needed for COM to act as console 575 */ 576 #include <i386/i386/cons.h> 577 578 comcnprobe(cp) 579 struct consdev *cp; 580 { 581 int unit; 582 583 /* locate the major number */ 584 for (commajor = 0; commajor < nchrdev; commajor++) 585 if (cdevsw[commajor].d_open == comopen) 586 break; 587 588 /* XXX: ick */ 589 unit = CONUNIT; 590 com_addr[CONUNIT] = CONADDR; 591 592 /* make sure hardware exists? XXX */ 593 594 /* initialize required fields */ 595 cp->cn_dev = makedev(commajor, unit); 596 cp->cn_tp = &com_tty[unit]; 597 #ifdef COMCONSOLE 598 cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 599 #else 600 cp->cn_pri = CN_NORMAL; 601 #endif 602 } 603 604 comcninit(cp) 605 struct consdev *cp; 606 { 607 int unit = UNIT(cp->cn_dev); 608 609 cominit(unit, comdefaultrate); 610 comconsole = unit; 611 comconsinit = 1; 612 } 613 614 cominit(unit, rate) 615 int unit, rate; 616 { 617 register int com; 618 int s; 619 short stat; 620 621 #ifdef lint 622 stat = unit; if (stat) return; 623 #endif 624 com = com_addr[unit]; 625 s = splhigh(); 626 outb(com+com_cfcr, CFCR_DLAB); 627 rate = ttspeedtab(comdefaultrate, comspeedtab); 628 outb(com+com_data, rate & 0xFF); 629 outb(com+com_ier, rate >> 8); 630 outb(com+com_cfcr, CFCR_8BITS); 631 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY); 632 outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 633 stat = inb(com+com_iir); 634 splx(s); 635 } 636 637 comcngetc(dev) 638 { 639 register com = com_addr[UNIT(dev)]; 640 short stat; 641 int c, s; 642 643 #ifdef lint 644 stat = dev; if (stat) return(0); 645 #endif 646 s = splhigh(); 647 while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0) 648 ; 649 c = inb(com+com_data); 650 stat = inb(com+com_iir); 651 splx(s); 652 return(c); 653 } 654 655 /* 656 * Console kernel output character routine. 657 */ 658 comcnputc(dev, c) 659 dev_t dev; 660 register int c; 661 { 662 register com = com_addr[UNIT(dev)]; 663 register int timo; 664 short stat; 665 int s = splhigh(); 666 667 #ifdef lint 668 stat = dev; if (stat) return; 669 #endif 670 #ifdef KGDB 671 if (dev != kgdb_dev) 672 #endif 673 if (comconsinit == 0) { 674 (void) cominit(UNIT(dev), comdefaultrate); 675 comconsinit = 1; 676 } 677 /* wait for any pending transmission to finish */ 678 timo = 50000; 679 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 680 ; 681 outb(com+com_data, c); 682 /* wait for this transmission to complete */ 683 timo = 1500000; 684 while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo) 685 ; 686 /* clear any interrupts generated by this transmission */ 687 stat = inb(com+com_iir); 688 splx(s); 689 } 690 #endif 691