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