1 /* $NetBSD: com.c,v 1.49 1995/04/17 12:08:44 cgd 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 <dev/isa/isavar.h> 64 #include <dev/isa/comreg.h> 65 #include <dev/ic/ns16550.h> 66 67 struct com_softc { 68 struct device sc_dev; 69 void *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((void *)); 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 isa_attach_args *ia = aux; 168 int 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 int 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 (ia->ia_irq != IRQUNK) 215 sc->sc_ih = isa_intr_establish(ia->ia_irq, ISA_IST_EDGE, 216 ISA_IPL_TTY, comintr, sc); 217 218 #ifdef KGDB 219 if (kgdb_dev == makedev(commajor, unit)) { 220 if (comconsole == unit) 221 kgdb_dev = -1; /* can't debug over console port */ 222 else { 223 (void) cominit(unit, kgdb_rate); 224 if (kgdb_debug_init) { 225 /* 226 * Print prefix of device name, 227 * let kgdb_connect print the rest. 228 */ 229 printf("%s: ", sc->sc_dev.dv_xname); 230 kgdb_connect(1); 231 } else 232 printf("%s: kgdb enabled\n", 233 sc->sc_dev.dv_xname); 234 } 235 } 236 #endif 237 238 if (sc->sc_dev.dv_unit == comconsole) { 239 /* 240 * Need to reset baud rate, etc. of next print so reset 241 * comconsinit. Also make sure console is always "hardwired". 242 */ 243 comconsinit = 0; 244 sc->sc_hwflags |= COM_HW_CONSOLE; 245 sc->sc_swflags |= COM_SW_SOFTCAR; 246 } 247 } 248 249 int 250 comopen(dev, flag, mode, p) 251 dev_t dev; 252 int flag, mode; 253 struct proc *p; 254 { 255 int unit = COMUNIT(dev); 256 struct com_softc *sc; 257 int iobase; 258 struct tty *tp; 259 int s; 260 int error = 0; 261 262 if (unit >= comcd.cd_ndevs) 263 return ENXIO; 264 sc = comcd.cd_devs[unit]; 265 if (!sc) 266 return ENXIO; 267 268 s = spltty(); 269 270 if (!com_tty[unit]) 271 tp = com_tty[unit] = ttymalloc(); 272 else 273 tp = com_tty[unit]; 274 275 tp->t_oproc = comstart; 276 tp->t_param = comparam; 277 tp->t_dev = dev; 278 if ((tp->t_state & TS_ISOPEN) == 0) { 279 tp->t_state |= TS_WOPEN; 280 ttychars(tp); 281 tp->t_iflag = TTYDEF_IFLAG; 282 tp->t_oflag = TTYDEF_OFLAG; 283 tp->t_cflag = TTYDEF_CFLAG; 284 if (sc->sc_swflags & COM_SW_CLOCAL) 285 tp->t_cflag |= CLOCAL; 286 if (sc->sc_swflags & COM_SW_CRTSCTS) 287 tp->t_cflag |= CRTSCTS; 288 if (sc->sc_swflags & COM_SW_MDMBUF) 289 tp->t_cflag |= MDMBUF; 290 tp->t_lflag = TTYDEF_LFLAG; 291 tp->t_ispeed = tp->t_ospeed = comdefaultrate; 292 comparam(tp, &tp->t_termios); 293 ttsetwater(tp); 294 295 iobase = sc->sc_iobase; 296 /* Set the FIFO threshold based on the receive speed. */ 297 if (sc->sc_hwflags & COM_HW_FIFO) 298 outb(iobase + com_fifo, 299 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | 300 (tp->t_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); 301 /* flush any pending I/O */ 302 (void) inb(iobase + com_lsr); 303 (void) inb(iobase + com_data); 304 /* you turn me on, baby */ 305 sc->sc_mcr = MCR_DTR | MCR_RTS; 306 if (!(sc->sc_hwflags & COM_HW_NOIEN)) 307 sc->sc_mcr |= MCR_IENABLE; 308 outb(iobase + com_mcr, sc->sc_mcr); 309 outb(iobase + com_ier, 310 IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC); 311 312 sc->sc_msr = inb(iobase + com_msr); 313 if (sc->sc_swflags & COM_SW_SOFTCAR || sc->sc_msr & MSR_DCD || 314 tp->t_cflag & MDMBUF) 315 tp->t_state |= TS_CARR_ON; 316 else 317 tp->t_state &= ~TS_CARR_ON; 318 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) { 319 splx(s); 320 return EBUSY; 321 } 322 323 /* wait for carrier if necessary */ 324 if ((flag & O_NONBLOCK) == 0) 325 while ((tp->t_cflag & CLOCAL) == 0 && 326 (tp->t_state & TS_CARR_ON) == 0) { 327 tp->t_state |= TS_WOPEN; 328 error = ttysleep(tp, (caddr_t)&tp->t_rawq, 329 TTIPRI | PCATCH, ttopen, 0); 330 if (error) { 331 /* XXX should turn off chip if we're the 332 only waiter */ 333 splx(s); 334 return error; 335 } 336 } 337 splx(s); 338 339 return (*linesw[tp->t_line].l_open)(dev, tp); 340 } 341 342 int 343 comclose(dev, flag, mode, p) 344 dev_t dev; 345 int flag, mode; 346 struct proc *p; 347 { 348 int unit = COMUNIT(dev); 349 struct com_softc *sc = comcd.cd_devs[unit]; 350 int iobase = sc->sc_iobase; 351 struct tty *tp = com_tty[unit]; 352 353 (*linesw[tp->t_line].l_close)(tp, flag); 354 #ifdef KGDB 355 /* do not disable interrupts if debugging */ 356 if (kgdb_dev != makedev(commajor, unit)) 357 #endif 358 { 359 bic(iobase + com_cfcr, CFCR_SBREAK); 360 outb(iobase + com_ier, 0); 361 if (tp->t_cflag & HUPCL && 362 (sc->sc_swflags & COM_SW_SOFTCAR) == 0) 363 /* XXX perhaps only clear DTR */ 364 outb(iobase + com_mcr, 0); 365 } 366 ttyclose(tp); 367 #ifdef notyet /* XXXX */ 368 if (unit != comconsole) { 369 ttyfree(tp); 370 com_tty[unit] = (struct tty *)NULL; 371 } 372 #endif 373 return 0; 374 } 375 376 int 377 comread(dev, uio, flag) 378 dev_t dev; 379 struct uio *uio; 380 int flag; 381 { 382 struct tty *tp = com_tty[COMUNIT(dev)]; 383 384 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 385 } 386 387 int 388 comwrite(dev, uio, flag) 389 dev_t dev; 390 struct uio *uio; 391 int flag; 392 { 393 struct tty *tp = com_tty[COMUNIT(dev)]; 394 395 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 396 } 397 398 static u_char 399 tiocm_xxx2mcr(data) 400 int data; 401 { 402 u_char m = 0; 403 404 if (data & TIOCM_DTR) 405 m |= MCR_DTR; 406 if (data & TIOCM_RTS) 407 m |= MCR_RTS; 408 return m; 409 } 410 411 int 412 comioctl(dev, cmd, data, flag, p) 413 dev_t dev; 414 u_long cmd; 415 caddr_t data; 416 int flag; 417 struct proc *p; 418 { 419 int unit = COMUNIT(dev); 420 struct com_softc *sc = comcd.cd_devs[unit]; 421 int iobase = sc->sc_iobase; 422 struct tty *tp = com_tty[unit]; 423 int error; 424 425 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 426 if (error >= 0) 427 return error; 428 error = ttioctl(tp, cmd, data, flag, p); 429 if (error >= 0) 430 return error; 431 432 switch (cmd) { 433 case TIOCSBRK: 434 bis(iobase + com_cfcr, CFCR_SBREAK); 435 break; 436 case TIOCCBRK: 437 bic(iobase + com_cfcr, CFCR_SBREAK); 438 break; 439 case TIOCSDTR: 440 outb(iobase + com_mcr, sc->sc_mcr |= (MCR_DTR | MCR_RTS)); 441 break; 442 case TIOCCDTR: 443 outb(iobase + com_mcr, sc->sc_mcr &= ~(MCR_DTR | MCR_RTS)); 444 break; 445 case TIOCMSET: 446 sc->sc_mcr &= ~(MCR_DTR | MCR_RTS); 447 case TIOCMBIS: 448 outb(iobase + com_mcr, 449 sc->sc_mcr |= tiocm_xxx2mcr(*(int *)data)); 450 break; 451 case TIOCMBIC: 452 outb(iobase + com_mcr, 453 sc->sc_mcr &= ~tiocm_xxx2mcr(*(int *)data)); 454 break; 455 case TIOCMGET: { 456 u_char m; 457 int bits = 0; 458 459 m = sc->sc_mcr; 460 if (m & MCR_DTR) 461 bits |= TIOCM_DTR; 462 if (m & MCR_RTS) 463 bits |= TIOCM_RTS; 464 m = sc->sc_msr; 465 if (m & MSR_DCD) 466 bits |= TIOCM_CD; 467 if (m & MSR_CTS) 468 bits |= TIOCM_CTS; 469 if (m & MSR_DSR) 470 bits |= TIOCM_DSR; 471 if (m & (MSR_RI | MSR_TERI)) 472 bits |= TIOCM_RI; 473 if (inb(iobase + com_ier)) 474 bits |= TIOCM_LE; 475 *(int *)data = bits; 476 break; 477 } 478 case TIOCGFLAGS: { 479 int bits = 0; 480 481 if (sc->sc_swflags & COM_SW_SOFTCAR) 482 bits |= TIOCFLAG_SOFTCAR; 483 if (sc->sc_swflags & COM_SW_CLOCAL) 484 bits |= TIOCFLAG_CLOCAL; 485 if (sc->sc_swflags & COM_SW_CRTSCTS) 486 bits |= TIOCFLAG_CRTSCTS; 487 if (sc->sc_swflags & COM_SW_MDMBUF) 488 bits |= TIOCFLAG_MDMBUF; 489 490 *(int *)data = bits; 491 break; 492 } 493 case TIOCSFLAGS: { 494 int userbits, driverbits = 0; 495 496 error = suser(p->p_ucred, &p->p_acflag); 497 if (error != 0) 498 return(EPERM); 499 500 userbits = *(int *)data; 501 if ((userbits & TIOCFLAG_SOFTCAR) || 502 (sc->sc_hwflags & COM_HW_CONSOLE)) 503 driverbits |= COM_SW_SOFTCAR; 504 if (userbits & TIOCFLAG_CLOCAL) 505 driverbits |= COM_SW_CLOCAL; 506 if (userbits & TIOCFLAG_CRTSCTS) 507 driverbits |= COM_SW_CRTSCTS; 508 if (userbits & TIOCFLAG_MDMBUF) 509 driverbits |= COM_SW_MDMBUF; 510 511 sc->sc_swflags = driverbits; 512 break; 513 } 514 default: 515 return ENOTTY; 516 } 517 518 return 0; 519 } 520 521 int 522 comparam(tp, t) 523 struct tty *tp; 524 struct termios *t; 525 { 526 struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; 527 int iobase = sc->sc_iobase; 528 int ospeed = comspeed(t->c_ospeed); 529 u_char cfcr; 530 int s; 531 532 /* check requested parameters */ 533 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 534 return EINVAL; 535 536 switch (t->c_cflag & CSIZE) { 537 case CS5: 538 cfcr = CFCR_5BITS; 539 break; 540 case CS6: 541 cfcr = CFCR_6BITS; 542 break; 543 case CS7: 544 cfcr = CFCR_7BITS; 545 break; 546 case CS8: 547 cfcr = CFCR_8BITS; 548 break; 549 } 550 if (t->c_cflag & PARENB) { 551 cfcr |= CFCR_PENAB; 552 if ((t->c_cflag & PARODD) == 0) 553 cfcr |= CFCR_PEVEN; 554 } 555 if (t->c_cflag & CSTOPB) 556 cfcr |= CFCR_STOPB; 557 558 s = spltty(); 559 560 if (ospeed == 0) 561 outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_DTR); 562 563 /* 564 * Set the FIFO threshold based on the receive speed, if we are 565 * changing it. 566 * 567 * XXX 568 * It would be better if we waited for the FIFO to empty, so we don't 569 * lose any in-transit characters. 570 */ 571 if (tp->t_ispeed != t->c_ispeed) { 572 if (sc->sc_hwflags & COM_HW_FIFO) 573 outb(iobase + com_fifo, 574 FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | 575 (t->c_ispeed <= 1200 ? FIFO_TRIGGER_1 : FIFO_TRIGGER_8)); 576 } 577 578 outb(iobase + com_cfcr, cfcr | CFCR_DLAB); 579 outb(iobase + com_dlbl, ospeed); 580 outb(iobase + com_dlbh, ospeed>>8); 581 outb(iobase + com_cfcr, cfcr); 582 583 if (ospeed != 0) 584 outb(iobase + com_mcr, sc->sc_mcr |= MCR_DTR); 585 586 /* When not using CRTSCTS, RTS follows DTR. */ 587 if ((t->c_cflag & CRTSCTS) == 0) { 588 if (sc->sc_mcr & MCR_DTR) { 589 if ((sc->sc_mcr & MCR_RTS) == 0) 590 outb(iobase + com_mcr, sc->sc_mcr |= MCR_RTS); 591 } else { 592 if (sc->sc_mcr & MCR_RTS) 593 outb(iobase + com_mcr, sc->sc_mcr &= ~MCR_RTS); 594 } 595 } 596 597 /* 598 * If CTS is off and CRTSCTS is changed, we must toggle TS_TTSTOP. 599 * XXX should be done at tty layer. 600 */ 601 if ((sc->sc_msr & MSR_CTS) == 0 && 602 (tp->t_cflag & CRTSCTS) != (t->c_cflag & CRTSCTS)) { 603 if ((t->c_cflag & CRTSCTS) == 0) { 604 tp->t_state &= ~TS_TTSTOP; 605 (*linesw[tp->t_line].l_start)(tp); 606 } else 607 tp->t_state |= TS_TTSTOP; 608 } 609 610 /* 611 * If DCD is off and MDMBUF is changed, we must toggle TS_TTSTOP. 612 * XXX should be done at tty layer. 613 */ 614 if ((sc->sc_swflags & COM_SW_SOFTCAR) == 0 && 615 (sc->sc_msr & MSR_DCD) == 0 && 616 (tp->t_cflag & MDMBUF) != (t->c_cflag & MDMBUF)) { 617 if ((t->c_cflag & MDMBUF) == 0) { 618 tp->t_state &= ~TS_TTSTOP; 619 (*linesw[tp->t_line].l_start)(tp); 620 } else 621 tp->t_state |= TS_TTSTOP; 622 } 623 624 /* and copy to tty */ 625 tp->t_ispeed = t->c_ispeed; 626 tp->t_ospeed = t->c_ospeed; 627 tp->t_cflag = t->c_cflag; 628 629 splx(s); 630 return 0; 631 } 632 633 void 634 comstart(tp) 635 struct tty *tp; 636 { 637 struct com_softc *sc = comcd.cd_devs[COMUNIT(tp->t_dev)]; 638 int iobase = sc->sc_iobase; 639 int s; 640 641 s = spltty(); 642 if (tp->t_state & (TS_TTSTOP | TS_BUSY)) 643 goto out; 644 #if 0 /* XXXX I think this is handled adequately by commint() and comparam(). */ 645 if (tp->t_cflag & CRTSCTS && (sc->sc_mcr & MSR_CTS) == 0) 646 goto out; 647 #endif 648 if (tp->t_outq.c_cc <= tp->t_lowat) { 649 if (tp->t_state & TS_ASLEEP) { 650 tp->t_state &= ~TS_ASLEEP; 651 wakeup((caddr_t)&tp->t_outq); 652 } 653 selwakeup(&tp->t_wsel); 654 } 655 if (tp->t_outq.c_cc == 0) 656 goto out; 657 tp->t_state |= TS_BUSY; 658 if ((inb(iobase + com_lsr) & LSR_TXRDY) == 0) 659 goto out; 660 if (sc->sc_hwflags & COM_HW_FIFO) { 661 u_char buffer[16], *cp = buffer; 662 int n = q_to_b(&tp->t_outq, cp, sizeof buffer); 663 do { 664 outb(iobase + com_data, *cp++); 665 } while (--n); 666 } else 667 outb(iobase + com_data, getc(&tp->t_outq)); 668 out: 669 splx(s); 670 } 671 672 /* 673 * Stop output on a line. 674 */ 675 void 676 comstop(tp, flag) 677 struct tty *tp; 678 { 679 int s; 680 681 s = spltty(); 682 if (tp->t_state & TS_BUSY) 683 if ((tp->t_state & TS_TTSTOP) == 0) 684 tp->t_state |= TS_FLUSH; 685 splx(s); 686 } 687 688 static inline void 689 comeint(sc, stat) 690 struct com_softc *sc; 691 int stat; 692 { 693 int iobase = sc->sc_iobase; 694 int unit = sc->sc_dev.dv_unit; 695 struct tty *tp = com_tty[unit]; 696 int c; 697 698 c = inb(iobase + com_data); 699 if ((tp->t_state & TS_ISOPEN) == 0) { 700 #ifdef KGDB 701 /* we don't care about parity errors */ 702 if (((stat & (LSR_BI | LSR_FE | LSR_PE)) == LSR_PE) && 703 kgdb_dev == makedev(commajor, unit) && c == FRAME_END) 704 kgdb_connect(0); /* trap into kgdb */ 705 #endif 706 return; 707 } 708 if (stat & (LSR_BI | LSR_FE)) 709 c |= TTY_FE; 710 else if (stat & LSR_PE) 711 c |= TTY_PE; 712 if (stat & LSR_OE) { 713 if (sc->sc_overflows++ == 0) 714 timeout(comdiag, sc, 60 * hz); 715 } 716 /* XXXX put in FIFO and process later */ 717 (*linesw[tp->t_line].l_rint)(c, tp); 718 } 719 720 static inline void 721 commint(sc) 722 struct com_softc *sc; 723 { 724 int iobase = sc->sc_iobase; 725 struct tty *tp = com_tty[sc->sc_dev.dv_unit]; 726 u_char msr, delta; 727 728 msr = inb(iobase + com_msr); 729 delta = msr ^ sc->sc_msr; 730 sc->sc_msr = msr; 731 732 if (delta & MSR_DCD && (sc->sc_swflags & COM_SW_SOFTCAR) == 0) { 733 if (msr & MSR_DCD) 734 (void)(*linesw[tp->t_line].l_modem)(tp, 1); 735 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 736 outb(iobase + com_mcr, 737 sc->sc_mcr &= ~(MCR_DTR | MCR_RTS)); 738 } 739 if (delta & MSR_CTS && tp->t_cflag & CRTSCTS) { 740 /* the line is up and we want to do rts/cts flow control */ 741 if (msr & MSR_CTS) { 742 tp->t_state &= ~TS_TTSTOP; 743 (*linesw[tp->t_line].l_start)(tp); 744 } else 745 tp->t_state |= TS_TTSTOP; 746 } 747 } 748 749 void 750 comdiag(arg) 751 void *arg; 752 { 753 struct com_softc *sc = arg; 754 int overflows; 755 int s; 756 757 s = spltty(); 758 overflows = sc->sc_overflows; 759 sc->sc_overflows = 0; 760 splx(s); 761 762 if (overflows) 763 log(LOG_WARNING, "%s: %d silo overflow%s\n", 764 sc->sc_dev.dv_xname, overflows, overflows == 1 ? "" : "s"); 765 } 766 767 int 768 comintr(arg) 769 void *arg; 770 { 771 struct com_softc *sc = arg; 772 int iobase = sc->sc_iobase; 773 struct tty *tp; 774 u_char code; 775 776 code = inb(iobase + com_iir) & IIR_IMASK; 777 if (code & IIR_NOPEND) 778 return 0; 779 780 for (;;) { 781 if (code & IIR_RXRDY) { 782 tp = com_tty[sc->sc_dev.dv_unit]; 783 /* XXXX put in FIFO and process later */ 784 while (code = (inb(iobase + com_lsr) & LSR_RCV_MASK)) { 785 if (code & LSR_RXRDY) { 786 code = inb(iobase + com_data); 787 if (tp->t_state & TS_ISOPEN) 788 (*linesw[tp->t_line].l_rint)(code, tp); 789 #ifdef KGDB 790 else { 791 if (kgdb_dev == makedev(commajor, unit) && 792 code == FRAME_END) 793 kgdb_connect(0); 794 } 795 #endif 796 } else 797 comeint(sc, code); 798 } 799 } else if (code == IIR_TXRDY) { 800 tp = com_tty[sc->sc_dev.dv_unit]; 801 tp->t_state &= ~TS_BUSY; 802 if (tp->t_state & TS_FLUSH) 803 tp->t_state &= ~TS_FLUSH; 804 else 805 if (tp->t_line) 806 (*linesw[tp->t_line].l_start)(tp); 807 else 808 comstart(tp); 809 } else if (code == IIR_MLSC) { 810 commint(sc); 811 } else { 812 log(LOG_WARNING, "%s: weird interrupt: iir=0x%02x\n", 813 sc->sc_dev.dv_xname, code); 814 } 815 code = inb(iobase + com_iir) & IIR_IMASK; 816 if (code & IIR_NOPEND) 817 return 1; 818 } 819 } 820 821 /* 822 * Following are all routines needed for COM to act as console 823 */ 824 #include <dev/cons.h> 825 826 void 827 comcnprobe(cp) 828 struct consdev *cp; 829 { 830 831 if (!comprobe1(CONADDR)) { 832 cp->cn_pri = CN_DEAD; 833 return; 834 } 835 836 /* locate the major number */ 837 for (commajor = 0; commajor < nchrdev; commajor++) 838 if (cdevsw[commajor].d_open == comopen) 839 break; 840 841 /* initialize required fields */ 842 cp->cn_dev = makedev(commajor, CONUNIT); 843 #ifdef COMCONSOLE 844 cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 845 #else 846 cp->cn_pri = CN_NORMAL; 847 #endif 848 } 849 850 void 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 int 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 int 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 void 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