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