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.5 (Berkeley) 05/16/91 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 "param.h" 17 #include "systm.h" 18 #include "ioctl.h" 19 #include "tty.h" 20 #include "proc.h" 21 #include "user.h" 22 #include "conf.h" 23 #include "file.h" 24 #include "uio.h" 25 #include "kernel.h" 26 #include "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 int comprobe(), comattach(), comintr(), comstart(), comparam(); 33 34 struct isa_driver comdriver = { 35 comprobe, comattach, "com" 36 }; 37 38 int comsoftCAR; 39 int com_active; 40 int com_hasfifo; 41 int ncom = NCOM; 42 #ifdef COMCONSOLE 43 int comconsole = COMCONSOLE; 44 #else 45 int comconsole = -1; 46 #endif 47 int comconsinit; 48 int comdefaultrate = TTYDEF_SPEED; 49 int commajor; 50 short com_addr[NCOM]; 51 struct tty com_tty[NCOM]; 52 53 struct speedtab comspeedtab[] = { 54 0, 0, 55 50, COMBRD(50), 56 75, COMBRD(75), 57 110, COMBRD(110), 58 134, COMBRD(134), 59 150, COMBRD(150), 60 200, COMBRD(200), 61 300, COMBRD(300), 62 600, COMBRD(600), 63 1200, COMBRD(1200), 64 1800, COMBRD(1800), 65 2400, COMBRD(2400), 66 4800, COMBRD(4800), 67 9600, COMBRD(9600), 68 19200, COMBRD(19200), 69 38400, COMBRD(38400), 70 57600, COMBRD(57600), 71 -1, -1 72 }; 73 74 extern struct tty *constty; 75 #ifdef KGDB 76 #include "machine/remote-sl.h" 77 78 extern int kgdb_dev; 79 extern int kgdb_rate; 80 extern int kgdb_debug_init; 81 #endif 82 83 #define UNIT(x) minor(x) 84 85 comprobe(dev) 86 struct isa_device *dev; 87 { 88 /* force access to id reg */ 89 outb(dev->id_iobase+com_cfcr, 0); 90 outb(dev->id_iobase+com_iir, 0); 91 if ((inb(dev->id_iobase+com_iir) & 0x38) == 0) 92 return(1); 93 return(1); 94 95 } 96 97 98 int 99 comattach(isdp) 100 struct isa_device *isdp; 101 { 102 struct tty *tp; 103 u_char unit; 104 int port = isdp->id_iobase; 105 106 unit = isdp->id_unit; 107 if (unit == comconsole) 108 DELAY(100000); 109 com_addr[unit] = port; 110 com_active |= 1 << unit; 111 comsoftCAR |= 1 << unit; /* XXX */ 112 113 /* look for a NS 16550AF UART with FIFOs */ 114 outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14); 115 DELAY(100); 116 if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) 117 com_hasfifo |= 1 << unit; 118 119 outb(port+com_ier, 0); 120 outb(port+com_mcr, 0 | MCR_IENABLE); 121 #ifdef KGDB 122 if (kgdb_dev == makedev(commajor, unit)) { 123 if (comconsole == unit) 124 kgdb_dev = -1; /* can't debug over console port */ 125 else { 126 (void) cominit(unit, kgdb_rate); 127 if (kgdb_debug_init) { 128 /* 129 * Print prefix of device name, 130 * let kgdb_connect print the rest. 131 */ 132 printf("com%d: ", unit); 133 kgdb_connect(1); 134 } else 135 printf("com%d: kgdb enabled\n", unit); 136 } 137 } 138 #endif 139 /* 140 * Need to reset baud rate, etc. of next print so reset comconsinit. 141 * Also make sure console is always "hardwired" 142 */ 143 if (unit == comconsole) { 144 comconsinit = 0; 145 comsoftCAR |= (1 << unit); 146 } 147 return (1); 148 } 149 150 /* ARGSUSED */ 151 #ifdef __STDC__ 152 comopen(dev_t dev, int flag, int mode, struct proc *p) 153 #else 154 comopen(dev, flag, mode, p) 155 dev_t dev; 156 int flag, mode; 157 struct proc *p; 158 #endif 159 { 160 register struct tty *tp; 161 register int unit; 162 int error = 0; 163 164 unit = UNIT(dev); 165 if (unit >= NCOM || (com_active & (1 << unit)) == 0) 166 return (ENXIO); 167 tp = &com_tty[unit]; 168 tp->t_oproc = comstart; 169 tp->t_param = comparam; 170 tp->t_dev = dev; 171 if ((tp->t_state & TS_ISOPEN) == 0) { 172 tp->t_state |= TS_WOPEN; 173 ttychars(tp); 174 if (tp->t_ispeed == 0) { 175 tp->t_iflag = TTYDEF_IFLAG; 176 tp->t_oflag = TTYDEF_OFLAG; 177 tp->t_cflag = TTYDEF_CFLAG; 178 tp->t_lflag = TTYDEF_LFLAG; 179 tp->t_ispeed = tp->t_ospeed = comdefaultrate; 180 } 181 comparam(tp, &tp->t_termios); 182 ttsetwater(tp); 183 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 184 return (EBUSY); 185 (void) spltty(); 186 (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET); 187 if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD)) 188 tp->t_state |= TS_CARR_ON; 189 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 190 (tp->t_state & TS_CARR_ON) == 0) { 191 tp->t_state |= TS_WOPEN; 192 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 193 ttopen, 0)) 194 break; 195 } 196 (void) spl0(); 197 if (error == 0) 198 error = (*linesw[tp->t_line].l_open)(dev, tp); 199 return (error); 200 } 201 202 /*ARGSUSED*/ 203 comclose(dev, flag, mode, p) 204 dev_t dev; 205 int flag, mode; 206 struct proc *p; 207 { 208 register struct tty *tp; 209 register com; 210 register int unit; 211 212 unit = UNIT(dev); 213 com = com_addr[unit]; 214 tp = &com_tty[unit]; 215 (*linesw[tp->t_line].l_close)(tp, flag); 216 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 217 #ifdef KGDB 218 /* do not disable interrupts if debugging */ 219 if (kgdb_dev != makedev(commajor, unit)) 220 #endif 221 outb(com+com_ier, 0); 222 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 223 (tp->t_state&TS_ISOPEN) == 0) 224 (void) commctl(dev, 0, DMSET); 225 ttyclose(tp); 226 return(0); 227 } 228 229 comread(dev, uio, flag) 230 dev_t dev; 231 struct uio *uio; 232 { 233 register struct tty *tp = &com_tty[UNIT(dev)]; 234 235 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 236 } 237 238 comwrite(dev, uio, flag) 239 dev_t dev; 240 struct uio *uio; 241 { 242 int unit = UNIT(dev); 243 register struct tty *tp = &com_tty[unit]; 244 245 /* 246 * (XXX) We disallow virtual consoles if the physical console is 247 * a serial port. This is in case there is a display attached that 248 * is not the console. In that situation we don't need/want the X 249 * server taking over the console. 250 */ 251 if (constty && unit == comconsole) 252 constty = NULL; 253 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 254 } 255 256 comintr(unit) 257 register int unit; 258 { 259 register com; 260 register u_char code; 261 register struct tty *tp; 262 263 com = com_addr[unit]; 264 while (1) { 265 code = inb(com+com_iir); 266 switch (code & IIR_IMASK) { 267 case IIR_NOPEND: 268 return (1); 269 case IIR_RXTOUT: 270 case IIR_RXRDY: 271 tp = &com_tty[unit]; 272 /* 273 * Process received bytes. Inline for speed... 274 */ 275 #ifdef KGDB 276 #define RCVBYTE() \ 277 code = inb(com+com_data); \ 278 if ((tp->t_state & TS_ISOPEN) == 0) { \ 279 if (kgdb_dev == makedev(commajor, unit) && \ 280 code == FRAME_END) \ 281 kgdb_connect(0); /* trap into kgdb */ \ 282 } else \ 283 (*linesw[tp->t_line].l_rint)(code, tp) 284 #else 285 #define RCVBYTE() \ 286 code = inb(com+com_data); \ 287 if (tp->t_state & TS_ISOPEN) \ 288 (*linesw[tp->t_line].l_rint)(code, tp) 289 #endif 290 291 RCVBYTE(); 292 293 if (com_hasfifo & (1 << unit)) 294 while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) { 295 if (code == LSR_RXRDY) { 296 RCVBYTE(); 297 } else 298 comeint(unit, code, com); 299 } 300 break; 301 case IIR_TXRDY: 302 tp = &com_tty[unit]; 303 tp->t_state &=~ (TS_BUSY|TS_FLUSH); 304 if (tp->t_line) 305 (*linesw[tp->t_line].l_start)(tp); 306 else 307 comstart(tp); 308 break; 309 case IIR_RLS: 310 comeint(unit, inb(com+com_lsr), com); 311 break; 312 default: 313 if (code & IIR_NOPEND) 314 return (1); 315 log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n", 316 unit, code); 317 /* fall through */ 318 case IIR_MLSC: 319 commint(unit, com); 320 break; 321 } 322 } 323 } 324 325 comeint(unit, stat, com) 326 register int unit, stat; 327 register com; 328 { 329 register struct tty *tp; 330 register int c; 331 332 tp = &com_tty[unit]; 333 c = inb(com+com_data); 334 if ((tp->t_state & TS_ISOPEN) == 0) { 335 #ifdef KGDB 336 /* we don't care about parity errors */ 337 if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) && 338 kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 339 kgdb_connect(0); /* trap into kgdb */ 340 #endif 341 return; 342 } 343 if (stat & (LSR_BI | LSR_FE)) 344 c |= TTY_FE; 345 else if (stat & LSR_PE) 346 c |= TTY_PE; 347 else if (stat & LSR_OE) 348 log(LOG_WARNING, "com%d: silo overflow\n", unit); 349 (*linesw[tp->t_line].l_rint)(c, tp); 350 } 351 352 commint(unit, com) 353 register int unit; 354 register com; 355 { 356 register struct tty *tp; 357 register int stat; 358 359 tp = &com_tty[unit]; 360 stat = inb(com+com_msr); 361 if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) { 362 if (stat & MSR_DCD) 363 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 364 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 365 outb(com+com_mcr, 366 inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE); 367 } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) && 368 (tp->t_flags & CRTSCTS)) { 369 /* the line is up and we want to do rts/cts flow control */ 370 if (stat & MSR_CTS) { 371 tp->t_state &=~ TS_TTSTOP; 372 ttstart(tp); 373 } else 374 tp->t_state |= TS_TTSTOP; 375 } 376 } 377 378 comioctl(dev, cmd, data, flag) 379 dev_t dev; 380 caddr_t data; 381 { 382 register struct tty *tp; 383 register int unit = UNIT(dev); 384 register com; 385 register int error; 386 387 tp = &com_tty[unit]; 388 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 389 if (error >= 0) 390 return (error); 391 error = ttioctl(tp, cmd, data, flag); 392 if (error >= 0) 393 return (error); 394 395 com = com_addr[unit]; 396 switch (cmd) { 397 398 case TIOCSBRK: 399 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK); 400 break; 401 402 case TIOCCBRK: 403 outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK); 404 break; 405 406 case TIOCSDTR: 407 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS); 408 break; 409 410 case TIOCCDTR: 411 (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC); 412 break; 413 414 case TIOCMSET: 415 (void) commctl(dev, *(int *)data, DMSET); 416 break; 417 418 case TIOCMBIS: 419 (void) commctl(dev, *(int *)data, DMBIS); 420 break; 421 422 case TIOCMBIC: 423 (void) commctl(dev, *(int *)data, DMBIC); 424 break; 425 426 case TIOCMGET: 427 *(int *)data = commctl(dev, 0, DMGET); 428 break; 429 430 default: 431 return (ENOTTY); 432 } 433 return (0); 434 } 435 436 comparam(tp, t) 437 register struct tty *tp; 438 register struct termios *t; 439 { 440 register com; 441 register int cfcr, cflag = t->c_cflag; 442 int unit = UNIT(tp->t_dev); 443 int ospeed = ttspeedtab(t->c_ospeed, comspeedtab); 444 445 /* check requested parameters */ 446 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 447 return(EINVAL); 448 /* and copy to tty */ 449 tp->t_ispeed = t->c_ispeed; 450 tp->t_ospeed = t->c_ospeed; 451 tp->t_cflag = cflag; 452 453 com = com_addr[unit]; 454 outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/); 455 if (ospeed == 0) { 456 (void) commctl(unit, 0, DMSET); /* hang up line */ 457 return(0); 458 } 459 outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB); 460 outb(com+com_data, ospeed & 0xFF); 461 outb(com+com_ier, ospeed >> 8); 462 switch (cflag&CSIZE) { 463 case CS5: 464 cfcr = CFCR_5BITS; break; 465 case CS6: 466 cfcr = CFCR_6BITS; break; 467 case CS7: 468 cfcr = CFCR_7BITS; break; 469 case CS8: 470 cfcr = CFCR_8BITS; break; 471 } 472 if (cflag&PARENB) { 473 cfcr |= CFCR_PENAB; 474 if ((cflag&PARODD) == 0) 475 cfcr |= CFCR_PEVEN; 476 } 477 if (cflag&CSTOPB) 478 cfcr |= CFCR_STOPB; 479 outb(com+com_cfcr, cfcr); 480 481 if (com_hasfifo & (1 << unit)) 482 outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14); 483 484 return(0); 485 } 486 487 comstart(tp) 488 register struct tty *tp; 489 { 490 register com; 491 int s, unit, c; 492 493 unit = UNIT(tp->t_dev); 494 com = com_addr[unit]; 495 s = spltty(); 496 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 497 goto out; 498 if (tp->t_outq.c_cc <= tp->t_lowat) { 499 if (tp->t_state&TS_ASLEEP) { 500 tp->t_state &= ~TS_ASLEEP; 501 wakeup((caddr_t)&tp->t_outq); 502 } 503 if (tp->t_wsel) { 504 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); 505 tp->t_wsel = 0; 506 tp->t_state &= ~TS_WCOLL; 507 } 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