1 /*- 2 * Copyright (c) 1993, 1994 Charles Hannum. 3 * Copyright (c) 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from: @(#)com.c 7.5 (Berkeley) 5/16/91 35 * $Id: com.c,v 1.31 1994/04/10 10:29:06 cgd Exp $ 36 */ 37 38 /* 39 * COM driver, based on HP dca driver 40 * uses National Semiconductor NS16450/NS16550AF UART 41 */ 42 #include "com.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/ioctl.h> 47 #include <sys/select.h> 48 #include <sys/tty.h> 49 #include <sys/proc.h> 50 #include <sys/user.h> 51 #include <sys/conf.h> 52 #include <sys/file.h> 53 #include <sys/uio.h> 54 #include <sys/kernel.h> 55 #include <sys/syslog.h> 56 #include <sys/types.h> 57 #include <sys/device.h> 58 59 #include <machine/cpu.h> 60 #include <machine/pio.h> 61 62 #include <i386/isa/isavar.h> 63 #include <i386/isa/comreg.h> 64 #include <i386/isa/ic/ns16550.h> 65 66 struct com_softc { 67 struct device sc_dev; 68 struct intrhand sc_ih; 69 70 u_short sc_iobase; 71 u_char sc_hwflags; 72 #define COM_HW_NOIEN 0x01 73 #define COM_HW_FIFO 0x02 74 #define COM_HW_CONSOLE 0x40 75 u_char sc_swflags; 76 #define COM_SW_SOFTCAR 0x01 77 #define COM_SW_CLOCAL 0x02 78 #define COM_SW_CRTSCTS 0x04 79 #define COM_SW_MDMBUF 0x08 80 u_char sc_msr, sc_mcr; 81 }; 82 /* XXXX should be in com_softc, but not ready for that yet */ 83 struct tty *com_tty[NCOM]; 84 85 int comprobe(); 86 void comattach(); 87 int comopen __P((dev_t, int, int, struct proc *)); 88 int comclose __P((dev_t, int, int, struct proc *)); 89 int comintr __P((struct com_softc *)); 90 int comparam __P((struct tty *, struct termios *)); 91 void comstart __P((struct tty *)); 92 93 struct cfdriver comcd = { 94 NULL, "com", comprobe, comattach, DV_TTY, sizeof(struct com_softc) 95 }; 96 97 int comdefaultrate = TTYDEF_SPEED; 98 #ifdef COMCONSOLE 99 int comconsole = COMCONSOLE; 100 #else 101 int comconsole = -1; 102 #endif 103 int comconsinit; 104 int commajor; 105 106 #ifdef KGDB 107 #include <machine/remote-sl.h> 108 extern int kgdb_dev; 109 extern int kgdb_rate; 110 extern int kgdb_debug_init; 111 #endif 112 113 #define COMUNIT(x) (minor(x)) 114 115 #define bis(c, b) do { const register u_short com_ad = (c); \ 116 outb(com_ad, inb(com_ad) | (b)); } while(0) 117 #define bic(c, b) do { const register u_short com_ad = (c); \ 118 outb(com_ad, inb(com_ad) & ~(b)); } while(0) 119 120 int 121 comspeed(speed) 122 long speed; 123 { 124 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ 125 126 int x, err; 127 128 if (speed == 0) 129 return 0; 130 if (speed < 0) 131 return -1; 132 x = divrnd((COM_FREQ / 16), speed); 133 if (x <= 0) 134 return -1; 135 err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000; 136 if (err < 0) 137 err = -err; 138 if (err > COM_TOLERANCE) 139 return -1; 140 return x; 141 142 #undef divrnd(n, q) 143 } 144 145 int 146 comprobe1(iobase) 147 u_short iobase; 148 { 149 150 /* force access to id reg */ 151 outb(iobase + com_cfcr, 0); 152 outb(iobase + com_iir, 0); 153 if (inb(iobase + com_iir) & 0x38) 154 return 0; 155 156 return 1; 157 } 158 159 int 160 comprobe(parent, self, aux) 161 struct device *parent, *self; 162 void *aux; 163 { 164 struct com_softc *sc = (void *)self; 165 struct isa_attach_args *ia = aux; 166 u_short iobase = ia->ia_iobase; 167 168 if (!comprobe1(iobase)) 169 return 0; 170 171 ia->ia_iosize = COM_NPORTS; 172 ia->ia_msize = 0; 173 return 1; 174 } 175 176 void 177 comattach(parent, self, aux) 178 struct device *parent, *self; 179 void *aux; 180 { 181 struct com_softc *sc = (void *)self; 182 struct isa_attach_args *ia = aux; 183 struct cfdata *cf = sc->sc_dev.dv_cfdata; 184 u_short iobase = ia->ia_iobase; 185 struct tty *tp; 186 187 sc->sc_iobase = iobase; 188 sc->sc_hwflags = cf->cf_flags & COM_HW_NOIEN; 189 sc->sc_swflags = 0; 190 191 if (sc->sc_dev.dv_unit == comconsole) 192 delay(1000); 193 194 /* look for a NS 16550AF UART with FIFOs */ 195 outb(iobase + com_fifo, 196 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); 197 delay(100); 198 if ((inb(iobase + com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK) 199 if ((inb(iobase + com_fifo) & FIFO_TRIGGER_14) == FIFO_TRIGGER_14) { 200 sc->sc_hwflags |= COM_HW_FIFO; 201 printf(": ns16550a, working fifo\n"); 202 } else 203 printf(": ns82550 or ns16550, broken fifo\n"); 204 else 205 printf(": ns82450 or ns16450, no fifo\n"); 206 outb(iobase + com_fifo, 0); 207 208 /* disable interrupts */ 209 outb(iobase + com_ier, 0); 210 outb(iobase + com_mcr, 0); 211 212 if (!parent) { /* XXX no master */ 213 sc->sc_ih.ih_fun = comintr; 214 sc->sc_ih.ih_arg = sc; 215 sc->sc_ih.ih_level = IPL_TTY; 216 intr_establish(ia->ia_irq, &sc->sc_ih); 217 } 218 219 #ifdef KGDB 220 if (kgdb_dev == makedev(commajor, unit)) { 221 if (comconsole == unit) 222 kgdb_dev = -1; /* can't debug over console port */ 223 else { 224 (void) cominit(unit, kgdb_rate); 225 if (kgdb_debug_init) { 226 /* 227 * Print prefix of device name, 228 * let kgdb_connect print the rest. 229 */ 230 printf("%s: ", sc->sc_dev.dv_xname); 231 kgdb_connect(1); 232 } else 233 printf("%s: kgdb enabled\n", 234 sc->sc_dev.dv_xname); 235 } 236 } 237 #endif 238 239 if (sc->sc_dev.dv_unit == comconsole) { 240 /* 241 * Need to reset baud rate, etc. of next print so reset 242 * comconsinit. Also make sure console is always "hardwired". 243 */ 244 comconsinit = 0; 245 sc->sc_hwflags |= COM_HW_CONSOLE; 246 sc->sc_swflags |= COM_SW_SOFTCAR; 247 } 248 } 249 250 int 251 comopen(dev, flag, mode, p) 252 dev_t dev; 253 int flag, mode; 254 struct proc *p; 255 { 256 int unit = COMUNIT(dev); 257 struct com_softc *sc; 258 u_short iobase; 259 struct tty *tp; 260 int s; 261 int error = 0; 262 263 if (unit >= comcd.cd_ndevs) 264 return ENXIO; 265 sc = comcd.cd_devs[unit]; 266 if (!sc) 267 return ENXIO; 268 269 s = spltty(); 270 271 if (!com_tty[unit]) 272 tp = com_tty[unit] = ttymalloc(); 273 else 274 tp = com_tty[unit]; 275 276 tp->t_oproc = comstart; 277 tp->t_param = comparam; 278 tp->t_dev = dev; 279 if ((tp->t_state & TS_ISOPEN) == 0) { 280 tp->t_state |= TS_WOPEN; 281 ttychars(tp); 282 tp->t_iflag = TTYDEF_IFLAG; 283 tp->t_oflag = TTYDEF_OFLAG; 284 tp->t_cflag = TTYDEF_CFLAG; 285 if (sc->sc_swflags & COM_SW_CLOCAL) 286 tp->t_cflag |= CLOCAL; 287 if (sc->sc_swflags & COM_SW_CRTSCTS) 288 tp->t_cflag |= CRTSCTS; 289 if (sc->sc_swflags & COM_SW_MDMBUF) 290 tp->t_cflag |= MDMBUF; 291 tp->t_lflag = TTYDEF_LFLAG; 292 tp->t_ispeed = tp->t_ospeed = comdefaultrate; 293 comparam(tp, &tp->t_termios); 294 ttsetwater(tp); 295 296 iobase = sc->sc_iobase; 297 /* flush any pending I/O */ 298 if (sc->sc_hwflags & COM_HW_FIFO) 299 outb(iobase + com_fifo, 300 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | 301 FIFO_TRIGGER_8); 302 (void) inb(iobase + com_lsr); 303 (void) inb(iobase + com_data); 304 /* you turn me on, baby */ 305 sc->sc_mcr = MCR_DTR | MCR_RTS; 306 if (!(sc->sc_hwflags & COM_HW_NOIEN)) 307 sc->sc_mcr |= MCR_IENABLE; 308 outb(iobase + com_mcr, sc->sc_mcr); 309 outb(iobase + com_ier, 310 IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); 311 312 sc->sc_msr = inb(iobase + com_msr); 313 if (sc->sc_swflags & COM_SW_SOFTCAR || sc->sc_msr & MSR_DCD || 314 tp->t_lflag&MDMBUF) 315 tp->t_state |= TS_CARR_ON; 316 else 317 tp->t_state &= ~TS_CARR_ON; 318 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { 319 splx(s); 320 return EBUSY; 321 } 322 323 /* wait for carrier if necessary */ 324 if ((flag & O_NONBLOCK) == 0) 325 while ((tp->t_cflag & CLOCAL) == 0 && 326 (tp->t_state & TS_CARR_ON) == 0) { 327 tp->t_state |= TS_WOPEN; 328 error = ttysleep(tp, (caddr_t)&tp->t_rawq, 329 TTIPRI | PCATCH, ttopen, 0); 330 if (error) { 331 /* XXX should turn off chip if we're the 332 only waiter */ 333 splx(s); 334 return error; 335 } 336 } 337 splx(s); 338 339 return (*linesw[tp->t_line].l_open)(dev, tp); 340 } 341 342 int 343 comclose(dev, flag, mode, p) 344 dev_t dev; 345 int flag, mode; 346 struct proc *p; 347 { 348 int unit = COMUNIT(dev); 349 struct com_softc *sc = comcd.cd_devs[unit]; 350 u_short iobase = sc->sc_iobase; 351 struct tty *tp = com_tty[unit]; 352 353 (*linesw[tp->t_line].l_close)(tp, flag); 354 #ifdef KGDB 355 /* do not disable interrupts if debugging */ 356 if (kgdb_dev != makedev(commajor, unit)) 357 #endif 358 { 359 bic(iobase + com_cfcr, CFCR_SBREAK); 360 outb(iobase + com_ier, 0); 361 if (tp->t_cflag & HUPCL && 362 (sc->sc_swflags & COM_SW_SOFTCAR) == 0) 363 /* XXX perhaps only clear DTR */ 364 outb(iobase + com_mcr, 0); 365 } 366 ttyclose(tp); 367 #ifdef notyet /* XXXX */ 368 if (unit != comconsole) { 369 ttyfree(tp); 370 com_tty[unit] = (struct tty *)NULL; 371 } 372 #endif 373 return 0; 374 } 375 376 int 377 comread(dev, uio, flag) 378 dev_t dev; 379 struct uio *uio; 380 int flag; 381 { 382 struct tty *tp = com_tty[COMUNIT(dev)]; 383 384 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 385 } 386 387 int 388 comwrite(dev, uio, flag) 389 dev_t dev; 390 struct uio *uio; 391 int flag; 392 { 393 struct tty *tp = com_tty[COMUNIT(dev)]; 394 395 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 396 } 397 398 static u_char 399 tiocm_xxx2mcr(data) 400 int data; 401 { 402 u_char m = 0; 403 404 if (data & TIOCM_DTR) 405 m |= MCR_DTR; 406 if (data & TIOCM_RTS) 407 m |= MCR_RTS; 408 return m; 409 } 410 411 int 412 comioctl(dev, cmd, data, flag, p) 413 dev_t dev; 414 int cmd; 415 caddr_t data; 416 int flag; 417 struct proc *p; 418 { 419 int unit = COMUNIT(dev); 420 struct com_softc *sc = comcd.cd_devs[unit]; 421 u_short iobase = sc->sc_iobase; 422 struct tty *tp = com_tty[unit]; 423 int error; 424 425 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 426 if (error >= 0) 427 return error; 428 error = ttioctl(tp, cmd, data, flag, p); 429 if (error >= 0) 430 return error; 431 432 switch (cmd) { 433 case TIOCSBRK: 434 bis(iobase + com_cfcr, CFCR_SBREAK); 435 break; 436 case TIOCCBRK: 437 bic(iobase + com_cfcr, CFCR_SBREAK); 438 break; 439 case TIOCSDTR: 440 outb(iobase + com_mcr, sc->sc_mcr |= (MCR_DTR | MCR_RTS)); 441 break; 442 case TIOCCDTR: 443 outb(iobase + com_mcr, sc->sc_mcr &= ~(MCR_DTR | MCR_RTS)); 444 break; 445 case TIOCMSET: 446 sc->sc_mcr &= ~(MCR_DTR | MCR_RTS); 447 case TIOCMBIS: 448 outb(iobase + com_mcr, 449 sc->sc_mcr |= tiocm_xxx2mcr(*(int *)data)); 450 break; 451 case TIOCMBIC: 452 outb(iobase + com_mcr, 453 sc->sc_mcr &= ~tiocm_xxx2mcr(*(int *)data)); 454 break; 455 case TIOCMGET: { 456 u_char m; 457 int bits = 0; 458 459 m = sc->sc_mcr; 460 if (m & MCR_DTR) 461 bits |= TIOCM_DTR; 462 if (m & MCR_RTS) 463 bits |= TIOCM_RTS; 464 m = sc->sc_msr; 465 if (m & MSR_DCD) 466 bits |= TIOCM_CD; 467 if (m & MSR_CTS) 468 bits |= TIOCM_CTS; 469 if (m & MSR_DSR) 470 bits |= TIOCM_DSR; 471 if (m & (MSR_RI | MSR_TERI)) 472 bits |= TIOCM_RI; 473 if (inb(iobase + com_ier)) 474 bits |= TIOCM_LE; 475 *(int *)data = bits; 476 break; 477 } 478 case TIOCGFLAGS: { 479 int bits = 0; 480 481 if (sc->sc_swflags & COM_SW_SOFTCAR) 482 bits |= TIOCFLAG_SOFTCAR; 483 if (sc->sc_swflags & COM_SW_CLOCAL) 484 bits |= TIOCFLAG_CLOCAL; 485 if (sc->sc_swflags & COM_SW_CRTSCTS) 486 bits |= TIOCFLAG_CRTSCTS; 487 if (sc->sc_swflags & COM_SW_MDMBUF) 488 bits |= TIOCFLAG_MDMBUF; 489 490 *(int *)data = bits; 491 break; 492 } 493 case TIOCSFLAGS: { 494 int userbits, driverbits = 0; 495 496 error = suser(p->p_ucred, &p->p_acflag); 497 if (error != 0) 498 return(EPERM); 499 500 userbits = *(int *)data; 501 if ((userbits & TIOCFLAG_SOFTCAR) || 502 (sc->sc_hwflags & COM_HW_CONSOLE)) 503 driverbits |= COM_SW_SOFTCAR; 504 if (userbits & TIOCFLAG_CLOCAL) 505 driverbits |= COM_SW_CLOCAL; 506 if (userbits & TIOCFLAG_CRTSCTS) 507 driverbits |= COM_SW_CRTSCTS; 508 if (userbits & TIOCFLAG_MDMBUF) 509 driverbits |= COM_SW_MDMBUF; 510 511 sc->sc_swflags = driverbits; 512 break; 513 } 514 default: 515 return ENOTTY; 516 } 517 518 return 0; 519 } 520 521 int 522 comparam(tp, t) 523 struct tty *tp; 524 struct termios *t; 525 { 526 struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; 527 u_short iobase = sc->sc_iobase; 528 int ospeed = comspeed(t->c_ospeed); 529 u_char cfcr; 530 int s; 531 532 /* check requested parameters */ 533 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 534 return EINVAL; 535 536 switch (t->c_cflag & CSIZE) { 537 case CS5: 538 cfcr = CFCR_5BITS; 539 break; 540 case CS6: 541 cfcr = CFCR_6BITS; 542 break; 543 case CS7: 544 cfcr = CFCR_7BITS; 545 break; 546 case CS8: 547 cfcr = CFCR_8BITS; 548 break; 549 } 550 if (t->c_cflag & PARENB) { 551 cfcr |= CFCR_PENAB; 552 if ((t->c_cflag & PARODD) == 0) 553 cfcr |= CFCR_PEVEN; 554 } 555 if (t->c_cflag & CSTOPB) 556 cfcr |= CFCR_STOPB; 557 558 s = spltty(); 559 560 /* and copy to tty */ 561 tp->t_ispeed = t->c_ispeed; 562 tp->t_ospeed = t->c_ospeed; 563 tp->t_cflag = t->c_cflag; 564 565 if (ospeed == 0) 566 outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_DTR); 567 else 568 outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR); 569 570 outb(iobase + com_cfcr, cfcr | CFCR_DLAB); 571 outb(iobase + com_dlbl, ospeed); 572 outb(iobase + com_dlbh, ospeed>>8); 573 outb(iobase + com_cfcr, cfcr); 574 575 /* When not using CRTSCTS, RTS follows DTR. */ 576 if ((t->c_cflag & CRTSCTS) == 0) { 577 if (sc->sc_mcr & MCR_DTR) { 578 if ((sc->sc_mcr & MCR_RTS) == 0) 579 outb(iobase + com_mcr, sc->sc_mcr |= MCR_RTS); 580 } else { 581 if (sc->sc_mcr & MCR_RTS) 582 outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_RTS); 583 } 584 } 585 586 /* 587 * If CTS is off and CRTSCTS is changed, we must toggle TS_TTSTOP. 588 * XXX should be done at tty layer. 589 */ 590 if ((sc->sc_msr & MSR_CTS) == 0 && 591 (tp->t_cflag & CRTSCTS) != (t->c_cflag & CRTSCTS)) { 592 if ((t->c_cflag & CRTSCTS) == 0) { 593 tp->t_state &= ~TS_TTSTOP; 594 ttstart(tp); 595 } else 596 tp->t_state |= TS_TTSTOP; 597 } 598 599 /* 600 * If DCD is off and MDMBUF is changed, we must toggle TS_TTSTOP. 601 * XXX should be done at tty layer. 602 */ 603 if ((sc->sc_swflags & COM_SW_SOFTCAR) == 0 && 604 (sc->sc_msr & MSR_DCD) == 0 && 605 (tp->t_cflag & MDMBUF) != (t->c_cflag & MDMBUF)) { 606 if ((t->c_cflag & MDMBUF) == 0) { 607 tp->t_state &= ~TS_TTSTOP; 608 ttstart(tp); 609 } else 610 tp->t_state |= TS_TTSTOP; 611 } 612 613 splx(s); 614 return 0; 615 } 616 617 void 618 comstart(tp) 619 struct tty *tp; 620 { 621 struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; 622 u_short iobase = sc->sc_iobase; 623 int s; 624 625 s = spltty(); 626 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) 627 goto out; 628 #if 0 /* XXXX I think this is handled adequately by commint() and comparam(). */ 629 if (tp->t_cflag & CRTSCTS && (sc->sc_mcr & MSR_CTS) == 0) 630 goto out; 631 #endif 632 if (tp->t_outq.c_cc <= tp->t_lowat) { 633 if (tp->t_state & TS_ASLEEP) { 634 tp->t_state &= ~TS_ASLEEP; 635 wakeup((caddr_t)&tp->t_outq); 636 } 637 selwakeup(&tp->t_wsel); 638 } 639 if (tp->t_outq.c_cc == 0) 640 goto out; 641 tp->t_state |= TS_BUSY; 642 if ((inb(iobase + com_lsr) & LSR_TXRDY) == 0) 643 goto out; 644 if (sc->sc_hwflags & COM_HW_FIFO) { 645 u_char buffer[16], *cp = buffer; 646 int n = q_to_b(&tp->t_outq, cp, sizeof buffer); 647 do { 648 outb(iobase + com_data, *cp++); 649 } while (--n); 650 } else 651 outb(iobase + com_data, getc(&tp->t_outq)); 652 out: 653 splx(s); 654 } 655 656 /* 657 * Stop output on a line. 658 */ 659 void 660 comstop(tp, flag) 661 struct tty *tp; 662 { 663 int s; 664 665 s = spltty(); 666 if (tp->t_state & TS_BUSY) 667 if ((tp->t_state & TS_TTSTOP) == 0) 668 tp->t_state |= TS_FLUSH; 669 splx(s); 670 } 671 672 static inline void 673 comeint(sc, stat) 674 struct com_softc *sc; 675 int stat; 676 { 677 u_short iobase = sc->sc_iobase; 678 int unit = sc->sc_dev.dv_unit; 679 struct tty *tp = com_tty[unit]; 680 int c; 681 682 c = inb(iobase + com_data); 683 if ((tp->t_state & TS_ISOPEN) == 0) { 684 #ifdef KGDB 685 /* we don't care about parity errors */ 686 if (((stat & (LSR_BI | LSR_FE | LSR_PE)) == LSR_PE) && 687 kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 688 kgdb_connect(0); /* trap into kgdb */ 689 #endif 690 return; 691 } 692 if (stat & (LSR_BI | LSR_FE)) 693 c |= TTY_FE; 694 else if (stat & LSR_PE) 695 c |= TTY_PE; 696 if (stat & LSR_OE) 697 log(LOG_WARNING, "%s: silo overflow\n", sc->sc_dev.dv_xname); 698 /* XXXX put in FIFO and process later */ 699 (*linesw[tp->t_line].l_rint)(c, tp); 700 } 701 702 static inline void 703 commint(sc) 704 struct com_softc *sc; 705 { 706 u_short iobase = sc->sc_iobase; 707 struct tty *tp = com_tty[sc->sc_dev.dv_unit]; 708 u_char msr, delta; 709 710 msr = inb(iobase + com_msr); 711 delta = msr ^ sc->sc_msr; 712 sc->sc_msr = msr; 713 714 if (delta & MSR_DCD && (sc->sc_swflags & COM_SW_SOFTCAR) == 0) { 715 if (msr & MSR_DCD) 716 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 717 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 718 outb(iobase + com_mcr, 719 sc->sc_mcr &= ~(MCR_DTR | MCR_RTS)); 720 } 721 if (delta & MSR_CTS && tp->t_cflag & CRTSCTS) { 722 /* the line is up and we want to do rts/cts flow control */ 723 if (msr & MSR_CTS) { 724 tp->t_state &= ~TS_TTSTOP; 725 ttstart(tp); 726 } else 727 tp->t_state |= TS_TTSTOP; 728 } 729 } 730 731 int 732 comintr(sc) 733 struct com_softc *sc; 734 { 735 u_short iobase = sc->sc_iobase; 736 struct tty *tp; 737 u_char code; 738 739 code = inb(iobase + com_iir) & IIR_IMASK; 740 if (code & IIR_NOPEND) 741 return 0; 742 743 for (;;) { 744 if (code & IIR_RXRDY) { 745 tp = com_tty[sc->sc_dev.dv_unit]; 746 /* XXXX put in FIFO and process later */ 747 while (code = (inb(iobase + com_lsr) & LSR_RCV_MASK)) { 748 if (code == LSR_RXRDY) { 749 code = inb(iobase + com_data); 750 if (tp->t_state & TS_ISOPEN) 751 (*linesw[tp->t_line].l_rint)(code, tp); 752 #ifdef KGDB 753 else { 754 if (kgdb_dev == makedev(commajor, unit) && 755 code == FRAME_END) 756 kgdb_connect(0); 757 } 758 #endif 759 } else 760 comeint(sc, code); 761 } 762 } else if (code == IIR_TXRDY) { 763 tp = com_tty[sc->sc_dev.dv_unit]; 764 tp->t_state &= ~TS_BUSY; 765 if (tp->t_state & TS_FLUSH) 766 tp->t_state &= ~TS_FLUSH; 767 else 768 if (tp->t_line) 769 (*linesw[tp->t_line].l_start)(tp); 770 else 771 comstart(tp); 772 } else if (code == IIR_MLSC) { 773 commint(sc); 774 } else { 775 log(LOG_WARNING, "%s: weird interrupt: iir=0x%02x\n", 776 sc->sc_dev.dv_xname, code); 777 } 778 code = inb(iobase + com_iir) & IIR_IMASK; 779 if (code & IIR_NOPEND) 780 return 1; 781 } 782 } 783 784 /* 785 * Following are all routines needed for COM to act as console 786 */ 787 #include <dev/cons.h> 788 789 comcnprobe(cp) 790 struct consdev *cp; 791 { 792 793 if (!comprobe1(CONADDR)) { 794 cp->cn_pri = CN_DEAD; 795 return; 796 } 797 798 /* locate the major number */ 799 for (commajor = 0; commajor < nchrdev; commajor++) 800 if (cdevsw[commajor].d_open == comopen) 801 break; 802 803 /* initialize required fields */ 804 cp->cn_dev = makedev(commajor, CONUNIT); 805 #ifdef COMCONSOLE 806 cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 807 #else 808 cp->cn_pri = CN_NORMAL; 809 #endif 810 } 811 812 comcninit(cp) 813 struct consdev *cp; 814 { 815 816 cominit(CONUNIT, comdefaultrate); 817 comconsole = CONUNIT; 818 comconsinit = 0; 819 } 820 821 cominit(unit, rate) 822 int unit, rate; 823 { 824 int s = splhigh(); 825 u_short iobase = CONADDR; 826 u_char stat; 827 828 outb(iobase + com_cfcr, CFCR_DLAB); 829 rate = comspeed(comdefaultrate); 830 outb(iobase + com_dlbl, rate); 831 outb(iobase + com_dlbh, rate >> 8); 832 outb(iobase + com_cfcr, CFCR_8BITS); 833 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY); 834 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_4); 835 stat = inb(iobase + com_iir); 836 splx(s); 837 } 838 839 comcngetc(dev) 840 dev_t dev; 841 { 842 int s = splhigh(); 843 u_short iobase = CONADDR; 844 u_char stat, c; 845 846 while (((stat = inb(iobase + com_lsr)) & LSR_RXRDY) == 0) 847 ; 848 c = inb(iobase + com_data); 849 stat = inb(iobase + com_iir); 850 splx(s); 851 return c; 852 } 853 854 /* 855 * Console kernel output character routine. 856 */ 857 comcnputc(dev, c) 858 dev_t dev; 859 int c; 860 { 861 int s = splhigh(); 862 u_short iobase = CONADDR; 863 u_char stat; 864 register int timo; 865 866 #ifdef KGDB 867 if (dev != kgdb_dev) 868 #endif 869 if (comconsinit == 0) { 870 (void) cominit(COMUNIT(dev), comdefaultrate); 871 comconsinit = 1; 872 } 873 /* wait for any pending transmission to finish */ 874 timo = 50000; 875 while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo) 876 ; 877 outb(iobase + com_data, c); 878 /* wait for this transmission to complete */ 879 timo = 1500000; 880 while (((stat = inb(iobase + com_lsr)) & LSR_TXRDY) == 0 && --timo) 881 ; 882 /* clear any interrupts generated by this transmission */ 883 stat = inb(iobase + com_iir); 884 splx(s); 885 } 886