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