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