1 /* $NetBSD: ser.c,v 1.2 1997/08/27 06:59:19 leo Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Leo Weppelman. 9 * 10 * The driver structure is based on the i386 com-driver from Charles M. Hannum. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/ioctl.h> 43 #include <sys/select.h> 44 #include <sys/tty.h> 45 #include <sys/proc.h> 46 #include <sys/user.h> 47 #include <sys/conf.h> 48 #include <sys/file.h> 49 #include <sys/uio.h> 50 #include <sys/kernel.h> 51 #include <sys/syslog.h> 52 #include <sys/types.h> 53 #include <sys/device.h> 54 55 #include <m68k/asm_single.h> 56 57 #include <machine/iomap.h> 58 #include <machine/mfp.h> 59 #include <atari/atari/intr.h> 60 #include <atari/dev/ym2149reg.h> 61 #include <atari/dev/serreg.h> 62 63 /* #define SER_DEBUG */ 64 65 #define SERUNIT(x) (minor(x)) 66 67 /* XXX */ 68 #define CONSBAUD 9600 69 #define CONSCFLAG TTYDEF_CFLAG 70 /* end XXX */ 71 72 /* Macros to clear/set/test flags. */ 73 #define SET(t, f) (t) |= (f) 74 #define CLR(t, f) (t) &= ~(f) 75 #define ISSET(t, f) ((t) & (f)) 76 77 #define splserial() spl6() 78 79 /* Buffer size for character buffer */ 80 #define RXBUFSIZE 2048 /* More than enough.. */ 81 #define RXBUFMASK (RXBUFSIZE-1) /* Only iff previous is a power of 2 */ 82 #define RXHIWAT (RXBUFSIZE >> 2) 83 84 struct ser_softc { 85 struct device sc_dev; 86 struct tty *sc_tty; 87 88 int sc_overflows; 89 int sc_floods; 90 int sc_errors; 91 92 u_char sc_hwflags; 93 u_char sc_swflags; 94 95 int sc_ospeed; /* delay + timer-d data */ 96 u_char sc_imra; 97 u_char sc_imrb; 98 u_char sc_ucr; /* Uart control */ 99 u_char sc_msr; /* Modem status */ 100 u_char sc_tsr; /* Tranceiver status */ 101 u_char sc_rsr; /* Receiver status */ 102 u_char sc_mcr; /* (Pseudo) Modem ctrl. */ 103 104 u_char sc_msr_delta; 105 u_char sc_msr_mask; 106 u_char sc_mcr_active; 107 u_char sc_mcr_dtr, sc_mcr_rts, sc_msr_cts, sc_msr_dcd; 108 109 int sc_r_hiwat; 110 volatile u_int sc_rbget; 111 volatile u_int sc_rbput; 112 volatile u_int sc_rbavail; 113 u_char sc_rbuf[RXBUFSIZE]; 114 u_char sc_lbuf[RXBUFSIZE]; 115 116 volatile u_char sc_rx_blocked; 117 volatile u_char sc_rx_ready; 118 volatile u_char sc_tx_busy; 119 volatile u_char sc_tx_done; 120 volatile u_char sc_tx_stopped; 121 volatile u_char sc_st_check; 122 123 u_char *sc_tba; 124 int sc_tbc; 125 int sc_heldtbc; 126 127 volatile u_char sc_heldchange; 128 }; 129 130 /* 131 * For sc_hwflags: 132 */ 133 #define SER_HW_CONSOLE 0x01 134 135 cdev_decl(ser); 136 137 void ser_break __P((struct ser_softc *, int)); 138 void ser_hwiflow __P((struct ser_softc *, int)); 139 void ser_iflush __P((struct ser_softc *)); 140 void ser_loadchannelregs __P((struct ser_softc *)); 141 void ser_modem __P((struct ser_softc *, int)); 142 void serdiag __P((void *)); 143 int serhwiflow __P((struct tty *, int)); 144 void serinit __P((int)); 145 void serinitcons __P((int)); 146 int baud; 147 int sermintr __P((void *)); 148 int sertrintr __P((void *)); 149 int serparam __P((struct tty *, struct termios *)); 150 void serstart __P((struct tty *)); 151 152 struct consdev; 153 void sercnprobe __P((struct consdev *)); 154 void sercninit __P((struct consdev *)); 155 int sercngetc __P((dev_t)); 156 void sercnputc __P((dev_t, int)); 157 void sercnpollc __P((dev_t, int)); 158 159 static void sermsrint __P((struct ser_softc *, struct tty*)); 160 static void serrxint __P((struct ser_softc *, struct tty*)); 161 static int serspeed __P((long)); 162 static void sersoft __P((void *)); 163 static void sertxint __P((struct ser_softc *, struct tty*)); 164 165 static volatile int ser_softintr_scheduled = 0; 166 static int sermajor; 167 168 /* 169 * Autoconfig stuff 170 */ 171 static void serattach __P((struct device *, struct device *, void *)); 172 static int sermatch __P((struct device *, struct cfdata *, void *)); 173 174 struct cfattach ser_ca = { 175 sizeof(struct ser_softc), sermatch, serattach 176 }; 177 178 struct cfdriver ser_cd = { 179 NULL, "ser", DV_TTY, NULL, 0 180 }; 181 182 /*ARGSUSED*/ 183 static int 184 sermatch(pdp, cfp, auxp) 185 struct device *pdp; 186 struct cfdata *cfp; 187 void *auxp; 188 { 189 if (!strcmp((char *)auxp, "ser") && cfp->cf_unit == 0) 190 return (1); 191 return (0); 192 } 193 194 /*ARGSUSED*/ 195 static void 196 serattach(pdp, dp, auxp) 197 struct device *pdp, *dp; 198 void *auxp; 199 { 200 struct ser_softc *sc = (void *)dp; 201 202 if (intr_establish(1, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) 203 printf("serattach: Can't establish interrupt (1)\n"); 204 if (intr_establish(2, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) 205 printf("serattach: Can't establish interrupt (2)\n"); 206 if (intr_establish(14, USER_VEC, 0, (hw_ifun_t)sermintr, sc) == NULL) 207 printf("serattach: Can't establish interrupt (14)\n"); 208 if (intr_establish(9, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) 209 printf("serattach: Can't establish interrupt (9)\n"); 210 if (intr_establish(10, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) 211 printf("serattach: Can't establish interrupt (10)\n"); 212 if (intr_establish(11, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) 213 printf("serattach: Can't establish interrupt (11)\n"); 214 if (intr_establish(12, USER_VEC, 0, (hw_ifun_t)sertrintr, sc) == NULL) 215 printf("serattach: Can't establish interrupt (12)\n"); 216 217 ym2149_rts(1); 218 ym2149_dtr(1); 219 220 /* 221 * Enable but mask interrupts... 222 * XXX: Look at edge-sensitivity for DCD/CTS interrupts. 223 */ 224 MFP->mf_ierb |= IB_SCTS|IB_SDCD; 225 MFP->mf_iera |= IA_RRDY|IA_RERR|IA_TRDY|IA_TERR; 226 MFP->mf_imrb &= ~(IB_SCTS|IB_SDCD); 227 MFP->mf_imra &= ~(IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); 228 229 #ifdef SERCONSOLE 230 /* 231 * Activate serial console when DCD present... 232 */ 233 if (!(MFP->mf_gpip & MCR_DCD)) 234 SET(sc->sc_hwflags, SER_HW_CONSOLE); 235 #endif /* SERCONSOLE */ 236 237 printf("\n"); 238 if (ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) { 239 serinit(CONSBAUD); 240 printf("%s: console\n", sc->sc_dev.dv_xname); 241 } 242 } 243 244 #ifdef SER_DEBUG 245 void serstatus __P((struct ser_softc *, char *)); 246 void 247 serstatus(sc, str) 248 struct ser_softc *sc; 249 char *str; 250 { 251 struct tty *tp = sc->sc_tty; 252 253 printf("%s: %s %sclocal %sdcd %sts_carr_on %sdtr %stx_stopped\n", 254 sc->sc_dev.dv_xname, str, 255 ISSET(tp->t_cflag, CLOCAL) ? "+" : "-", 256 ISSET(sc->sc_msr, MCR_DCD) ? "+" : "-", 257 ISSET(tp->t_state, TS_CARR_ON) ? "+" : "-", 258 ISSET(sc->sc_mcr, MCR_DTR) ? "+" : "-", 259 sc->sc_tx_stopped ? "+" : "-"); 260 261 printf("%s: %s %scrtscts %scts %sts_ttstop %srts %srx_blocked\n", 262 sc->sc_dev.dv_xname, str, 263 ISSET(tp->t_cflag, CRTSCTS) ? "+" : "-", 264 ISSET(sc->sc_msr, MCR_CTS) ? "+" : "-", 265 ISSET(tp->t_state, TS_TTSTOP) ? "+" : "-", 266 ISSET(sc->sc_mcr, MCR_RTS) ? "+" : "-", 267 sc->sc_rx_blocked ? "+" : "-"); 268 } 269 #endif /* SER_DEBUG */ 270 271 int 272 seropen(dev, flag, mode, p) 273 dev_t dev; 274 int flag, mode; 275 struct proc *p; 276 { 277 int unit = SERUNIT(dev); 278 struct ser_softc *sc; 279 struct tty *tp; 280 int s, s2; 281 int error = 0; 282 283 if (unit >= ser_cd.cd_ndevs) 284 return (ENXIO); 285 sc = ser_cd.cd_devs[unit]; 286 if (!sc) 287 return (ENXIO); 288 289 if (!sc->sc_tty) { 290 tp = sc->sc_tty = ttymalloc(); 291 tty_attach(tp); 292 } else 293 tp = sc->sc_tty; 294 295 if (ISSET(tp->t_state, TS_ISOPEN) && 296 ISSET(tp->t_state, TS_XCLUDE) && 297 p->p_ucred->cr_uid != 0) 298 return (EBUSY); 299 300 s = spltty(); 301 302 /* We need to set this early for the benefit of sersoft(). */ 303 SET(tp->t_state, TS_WOPEN); 304 305 /* 306 * Do the following if this is a first open. 307 */ 308 if (!ISSET(tp->t_state, TS_ISOPEN)) { 309 struct termios t; 310 311 /* Turn on interrupts. */ 312 sc->sc_imra = IA_RRDY|IA_RERR|IA_TRDY|IA_TERR; 313 sc->sc_imrb = IB_SCTS|IB_SDCD; 314 single_inst_bset_b(MFP->mf_imra, sc->sc_imra); 315 single_inst_bset_b(MFP->mf_imrb, sc->sc_imrb); 316 317 /* Fetch the current modem control status, needed later. */ 318 sc->sc_msr = ~MFP->mf_gpip & (IO_SDCD|IO_SCTS|IO_SRI); 319 320 /* Add some entry points needed by the tty layer. */ 321 tp->t_oproc = serstart; 322 tp->t_param = serparam; 323 tp->t_hwiflow = serhwiflow; 324 tp->t_dev = dev; 325 326 /* 327 * Initialize the termios status to the defaults. Add in the 328 * sticky bits from TIOCSFLAGS. 329 */ 330 t.c_ispeed = 0; 331 if (ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) { 332 t.c_ospeed = CONSBAUD; 333 t.c_cflag = CONSCFLAG; 334 } 335 else { 336 t.c_ospeed = TTYDEF_SPEED; 337 t.c_cflag = TTYDEF_CFLAG; 338 } 339 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 340 SET(t.c_cflag, CLOCAL); 341 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 342 SET(t.c_cflag, CRTSCTS); 343 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 344 SET(t.c_cflag, MDMBUF); 345 tp->t_iflag = TTYDEF_IFLAG; 346 tp->t_oflag = TTYDEF_OFLAG; 347 tp->t_lflag = TTYDEF_LFLAG; 348 ttychars(tp); 349 (void) serparam(tp, &t); 350 ttsetwater(tp); 351 352 s2 = splserial(); 353 354 /* 355 * Turn on DTR. We must always do this, even if carrier is not 356 * present, because otherwise we'd have to use TIOCSDTR 357 * immediately after setting CLOCAL. We will drop DTR only on 358 * the next high-low transition of DCD, or by explicit request. 359 */ 360 ser_modem(sc, 1); 361 362 /* Clear the input ring, and unblock. */ 363 sc->sc_rbput = sc->sc_rbget = 0; 364 sc->sc_rbavail = RXBUFSIZE; 365 ser_iflush(sc); 366 sc->sc_rx_blocked = 0; 367 ser_hwiflow(sc, 0); 368 369 #ifdef SER_DEBUG 370 serstatus(sc, "seropen "); 371 #endif 372 373 splx(s2); 374 } 375 error = 0; 376 377 /* If we're doing a blocking open... */ 378 if (!ISSET(flag, O_NONBLOCK)) 379 /* ...then wait for carrier. */ 380 while (!ISSET(tp->t_state, TS_CARR_ON) && 381 !ISSET(tp->t_cflag, CLOCAL | MDMBUF)) { 382 error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, 383 ttopen, 0); 384 if (error) { 385 /* 386 * If the open was interrupted and nobody 387 * else has the device open, then hang up. 388 */ 389 if (!ISSET(tp->t_state, TS_ISOPEN)) { 390 ser_modem(sc, 0); 391 CLR(tp->t_state, TS_WOPEN); 392 ttwakeup(tp); 393 } 394 break; 395 } 396 SET(tp->t_state, TS_WOPEN); 397 } 398 399 splx(s); 400 if (error == 0) 401 error = (*linesw[tp->t_line].l_open)(dev, tp); 402 return (error); 403 } 404 405 int 406 serclose(dev, flag, mode, p) 407 dev_t dev; 408 int flag, mode; 409 struct proc *p; 410 { 411 int unit = SERUNIT(dev); 412 struct ser_softc *sc = ser_cd.cd_devs[unit]; 413 struct tty *tp = sc->sc_tty; 414 int s; 415 416 /* XXX This is for cons.c. */ 417 if (!ISSET(tp->t_state, TS_ISOPEN)) 418 return (0); 419 420 (*linesw[tp->t_line].l_close)(tp, flag); 421 ttyclose(tp); 422 423 /* If we were asserting flow control, then deassert it. */ 424 sc->sc_rx_blocked = 1; 425 ser_hwiflow(sc, 1); 426 427 /* Clear any break condition set with TIOCSBRK. */ 428 ser_break(sc, 0); 429 430 /* 431 * Hang up if necessary. Wait a bit, so the other side has time to 432 * notice even if we immediately open the port again. 433 */ 434 if (ISSET(tp->t_cflag, HUPCL)) { 435 ser_modem(sc, 0); 436 (void) tsleep(sc, TTIPRI, ttclos, hz); 437 } 438 439 s = splserial(); 440 /* Turn off interrupts. */ 441 CLR(sc->sc_imra, IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); 442 CLR(sc->sc_imrb, IB_SCTS|IB_SDCD); 443 single_inst_bclr_b(MFP->mf_imrb, IB_SCTS|IB_SDCD); 444 single_inst_bclr_b(MFP->mf_imra, IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); 445 splx(s); 446 447 return (0); 448 } 449 450 int 451 serread(dev, uio, flag) 452 dev_t dev; 453 struct uio *uio; 454 int flag; 455 { 456 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(dev)]; 457 struct tty *tp = sc->sc_tty; 458 459 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 460 } 461 462 int 463 serwrite(dev, uio, flag) 464 dev_t dev; 465 struct uio *uio; 466 int flag; 467 { 468 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(dev)]; 469 struct tty *tp = sc->sc_tty; 470 471 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 472 } 473 474 struct tty * 475 sertty(dev) 476 dev_t dev; 477 { 478 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(dev)]; 479 struct tty *tp = sc->sc_tty; 480 481 return (tp); 482 } 483 484 int 485 serioctl(dev, cmd, data, flag, p) 486 dev_t dev; 487 u_long cmd; 488 caddr_t data; 489 int flag; 490 struct proc *p; 491 { 492 int unit = SERUNIT(dev); 493 struct ser_softc *sc = ser_cd.cd_devs[unit]; 494 struct tty *tp = sc->sc_tty; 495 int error; 496 497 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 498 if (error >= 0) 499 return (error); 500 501 error = ttioctl(tp, cmd, data, flag, p); 502 if (error >= 0) 503 return (error); 504 505 switch (cmd) { 506 case TIOCSBRK: 507 ser_break(sc, 1); 508 break; 509 510 case TIOCCBRK: 511 ser_break(sc, 0); 512 break; 513 514 case TIOCSDTR: 515 ser_modem(sc, 1); 516 break; 517 518 case TIOCCDTR: 519 ser_modem(sc, 0); 520 break; 521 522 case TIOCGFLAGS: 523 *(int *)data = sc->sc_swflags; 524 break; 525 526 case TIOCSFLAGS: 527 error = suser(p->p_ucred, &p->p_acflag); 528 if (error) 529 return (error); 530 sc->sc_swflags = *(int *)data; 531 break; 532 533 case TIOCMSET: 534 case TIOCMBIS: 535 case TIOCMBIC: 536 case TIOCMGET: 537 default: 538 return (ENOTTY); 539 } 540 541 #ifdef SER_DEBUG 542 serstatus(sc, "serioctl "); 543 #endif 544 545 return (0); 546 } 547 548 void 549 ser_break(sc, onoff) 550 struct ser_softc *sc; 551 int onoff; 552 { 553 int s; 554 555 s = splserial(); 556 if (onoff) 557 SET(sc->sc_tsr, TSR_SBREAK); 558 else 559 CLR(sc->sc_tsr, TSR_SBREAK); 560 561 if (!sc->sc_heldchange) { 562 if (sc->sc_tx_busy) { 563 sc->sc_heldtbc = sc->sc_tbc; 564 sc->sc_tbc = 0; 565 sc->sc_heldchange = 1; 566 } else 567 ser_loadchannelregs(sc); 568 } 569 splx(s); 570 } 571 572 void 573 ser_modem(sc, onoff) 574 struct ser_softc *sc; 575 int onoff; 576 { 577 int s; 578 579 s = splserial(); 580 if (onoff) 581 SET(sc->sc_mcr, sc->sc_mcr_dtr); 582 else 583 CLR(sc->sc_mcr, sc->sc_mcr_dtr); 584 585 if (!sc->sc_heldchange) { 586 if (sc->sc_tx_busy) { 587 sc->sc_heldtbc = sc->sc_tbc; 588 sc->sc_tbc = 0; 589 sc->sc_heldchange = 1; 590 } else 591 ser_loadchannelregs(sc); 592 } 593 splx(s); 594 } 595 596 int 597 serparam(tp, t) 598 struct tty *tp; 599 struct termios *t; 600 { 601 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)]; 602 int ospeed = serspeed(t->c_ospeed); 603 u_char ucr; 604 int s; 605 606 /* check requested parameters */ 607 if (ospeed < 0) 608 return (EINVAL); 609 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 610 return (EINVAL); 611 612 sc->sc_rsr = RSR_ENAB; 613 sc->sc_tsr = TSR_ENAB; 614 615 ucr = UCR_CLKDIV; 616 617 switch (ISSET(t->c_cflag, CSIZE)) { 618 case CS5: 619 SET(ucr, UCR_5BITS); 620 break; 621 case CS6: 622 SET(ucr, UCR_6BITS); 623 break; 624 case CS7: 625 SET(ucr, UCR_7BITS); 626 break; 627 case CS8: 628 SET(ucr, UCR_8BITS); 629 break; 630 } 631 if (ISSET(t->c_cflag, PARENB)) { 632 SET(ucr, UCR_PENAB); 633 if (!ISSET(t->c_cflag, PARODD)) 634 SET(ucr, UCR_PEVEN); 635 } 636 if (ISSET(t->c_cflag, CSTOPB)) 637 SET(ucr, UCR_STOPB2); 638 else 639 SET(ucr, UCR_STOPB1); 640 641 s = splserial(); 642 643 sc->sc_ucr = ucr; 644 645 /* 646 * For the console, always force CLOCAL and !HUPCL, so that the port 647 * is always active. 648 */ 649 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 650 ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) { 651 SET(t->c_cflag, CLOCAL); 652 CLR(t->c_cflag, HUPCL); 653 } 654 655 /* 656 * If we're not in a mode that assumes a connection is present, then 657 * ignore carrier changes. 658 */ 659 if (ISSET(t->c_cflag, CLOCAL | MDMBUF)) 660 sc->sc_msr_dcd = 0; 661 else 662 sc->sc_msr_dcd = MCR_DCD; 663 /* 664 * Set the flow control pins depending on the current flow control 665 * mode. 666 */ 667 if (ISSET(t->c_cflag, CRTSCTS)) { 668 sc->sc_mcr_dtr = MCR_DTR; 669 sc->sc_mcr_rts = MCR_RTS; 670 sc->sc_msr_cts = MCR_CTS; 671 sc->sc_r_hiwat = RXHIWAT; 672 } else if (ISSET(t->c_cflag, MDMBUF)) { 673 /* 674 * For DTR/DCD flow control, make sure we don't toggle DTR for 675 * carrier detection. 676 */ 677 sc->sc_mcr_dtr = 0; 678 sc->sc_mcr_rts = MCR_DTR; 679 sc->sc_msr_cts = MCR_DCD; 680 sc->sc_r_hiwat = RXHIWAT; 681 } else { 682 /* 683 * If no flow control, then always set RTS. This will make 684 * the other side happy if it mistakenly thinks we're doing 685 * RTS/CTS flow control. 686 */ 687 sc->sc_mcr_dtr = MCR_DTR | MCR_RTS; 688 sc->sc_mcr_rts = 0; 689 sc->sc_msr_cts = 0; 690 sc->sc_r_hiwat = 0; 691 if (ISSET(sc->sc_mcr, MCR_DTR)) 692 SET(sc->sc_mcr, MCR_RTS); 693 else 694 CLR(sc->sc_mcr, MCR_RTS); 695 } 696 sc->sc_msr_mask = sc->sc_msr_cts | sc->sc_msr_dcd; 697 698 #if 0 699 if (ospeed == 0) 700 CLR(sc->sc_mcr, sc->sc_mcr_dtr); 701 else 702 SET(sc->sc_mcr, sc->sc_mcr_dtr); 703 #endif 704 705 sc->sc_ospeed = ospeed; 706 707 /* and copy to tty */ 708 tp->t_ispeed = 0; 709 tp->t_ospeed = t->c_ospeed; 710 tp->t_cflag = t->c_cflag; 711 712 if (!sc->sc_heldchange) { 713 if (sc->sc_tx_busy) { 714 sc->sc_heldtbc = sc->sc_tbc; 715 sc->sc_tbc = 0; 716 sc->sc_heldchange = 1; 717 } else 718 ser_loadchannelregs(sc); 719 } 720 721 splx(s); 722 723 /* 724 * Update the tty layer's idea of the carrier bit, in case we changed 725 * CLOCAL or MDMBUF. We don't hang up here; we only do that if we 726 * lose carrier while carrier detection is on. 727 */ 728 (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(sc->sc_msr, MCR_DCD)); 729 730 #ifdef SER_DEBUG 731 serstatus(sc, "serparam "); 732 #endif 733 734 /* XXXXX FIX ME */ 735 /* Block or unblock as needed. */ 736 if (!ISSET(t->c_cflag, CHWFLOW)) { 737 if (sc->sc_rx_blocked) { 738 sc->sc_rx_blocked = 0; 739 ser_hwiflow(sc, 0); 740 } 741 if (sc->sc_tx_stopped) { 742 sc->sc_tx_stopped = 0; 743 serstart(tp); 744 } 745 } else { 746 #if 0 747 sermsrint(sc, tp); 748 #endif 749 } 750 751 return (0); 752 } 753 754 void 755 ser_iflush(sc) 756 struct ser_softc *sc; 757 { 758 u_char tmp; 759 760 /* flush any pending I/O */ 761 while (ISSET(MFP->mf_rsr, RSR_CIP|RSR_BFULL)) 762 tmp = MFP->mf_udr; 763 } 764 765 void 766 ser_loadchannelregs(sc) 767 struct ser_softc *sc; 768 { 769 /* XXXXX necessary? */ 770 ser_iflush(sc); 771 772 /* 773 * No interrupts please... 774 */ 775 if((MFP->mf_imra & (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR)) != sc->sc_imra) { 776 printf("loadchannelregs: mf_imra: %x sc_imra: %x\n", (u_int)MFP->mf_imra, 777 (u_int)sc->sc_imra); 778 } 779 if((MFP->mf_imrb & (IB_SCTS|IB_SDCD)) != sc->sc_imrb) { 780 printf("loadchannelregs: mf_imrb: %x sc_imrb: %x\n", (u_int)MFP->mf_imrb, 781 (u_int)sc->sc_imrb); 782 } 783 single_inst_bclr_b(MFP->mf_imra, IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); 784 single_inst_bclr_b(MFP->mf_imrb, IB_SCTS|IB_SDCD); 785 786 MFP->mf_ucr = sc->sc_ucr; 787 MFP->mf_rsr = sc->sc_rsr; 788 MFP->mf_tsr = sc->sc_tsr; 789 790 single_inst_bclr_b(MFP->mf_tcdcr, 0x07); 791 MFP->mf_tddr = sc->sc_ospeed; 792 single_inst_bset_b(MFP->mf_tcdcr, (sc->sc_ospeed >> 8) & 0x0f); 793 794 sc->sc_mcr_active = sc->sc_mcr; 795 796 if (machineid & ATARI_HADES) { 797 /* PCB fault, wires exchanged..... */ 798 ym2149_rts(!(sc->sc_mcr_active & MCR_DTR)); 799 ym2149_dtr(!(sc->sc_mcr_active & MCR_RTS)); 800 } 801 else { 802 ym2149_rts(!(sc->sc_mcr_active & MCR_RTS)); 803 ym2149_dtr(!(sc->sc_mcr_active & MCR_DTR)); 804 } 805 806 single_inst_bset_b(MFP->mf_imra, sc->sc_imra); 807 single_inst_bset_b(MFP->mf_imrb, sc->sc_imrb); 808 } 809 810 int 811 serhwiflow(tp, block) 812 struct tty *tp; 813 int block; 814 { 815 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)]; 816 int s; 817 818 if (sc->sc_mcr_rts == 0) 819 return (0); 820 821 s = splserial(); 822 if (block) { 823 /* 824 * The tty layer is asking us to block input. 825 * If we already did it, just return TRUE. 826 */ 827 if (sc->sc_rx_blocked) 828 goto out; 829 sc->sc_rx_blocked = 1; 830 } else { 831 /* 832 * The tty layer is asking us to resume input. 833 * The input ring is always empty by now. 834 */ 835 sc->sc_rx_blocked = 0; 836 } 837 ser_hwiflow(sc, block); 838 out: 839 splx(s); 840 return (1); 841 } 842 843 /* 844 * (un)block input via hw flowcontrol 845 */ 846 void 847 ser_hwiflow(sc, block) 848 struct ser_softc *sc; 849 int block; 850 { 851 if (sc->sc_mcr_rts == 0) 852 return; 853 854 if (block) { 855 CLR(sc->sc_mcr, sc->sc_mcr_rts); 856 CLR(sc->sc_mcr_active, sc->sc_mcr_rts); 857 } else { 858 SET(sc->sc_mcr, sc->sc_mcr_rts); 859 SET(sc->sc_mcr_active, sc->sc_mcr_rts); 860 } 861 if (machineid & ATARI_HADES) { 862 /* PCB fault, wires exchanged..... */ 863 ym2149_dtr(sc->sc_mcr_active & MCR_RTS); 864 } 865 else { 866 ym2149_rts(sc->sc_mcr_active & MCR_RTS); 867 } 868 } 869 870 void 871 serstart(tp) 872 struct tty *tp; 873 { 874 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)]; 875 int s; 876 877 s = spltty(); 878 if (ISSET(tp->t_state, TS_BUSY)) 879 goto out; 880 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP)) 881 goto stopped; 882 883 if (sc->sc_tx_stopped) 884 goto stopped; 885 886 if (tp->t_outq.c_cc <= tp->t_lowat) { 887 if (ISSET(tp->t_state, TS_ASLEEP)) { 888 CLR(tp->t_state, TS_ASLEEP); 889 wakeup(&tp->t_outq); 890 } 891 selwakeup(&tp->t_wsel); 892 if (tp->t_outq.c_cc == 0) 893 goto stopped; 894 } 895 896 /* Grab the first contiguous region of buffer space. */ 897 { 898 u_char *tba; 899 int tbc; 900 901 tba = tp->t_outq.c_cf; 902 tbc = ndqb(&tp->t_outq, 0); 903 904 (void)splserial(); 905 906 sc->sc_tba = tba; 907 sc->sc_tbc = tbc; 908 } 909 910 SET(tp->t_state, TS_BUSY); 911 sc->sc_tx_busy = 1; 912 913 /* Enable transmit completion interrupts if necessary. */ 914 if (!ISSET(sc->sc_imra, IA_TRDY)) { 915 SET(sc->sc_imra, IA_TRDY|IA_TERR); 916 single_inst_bset_b(MFP->mf_imra, IA_TRDY|IA_TERR); 917 } 918 919 /* Output the first char */ 920 MFP->mf_udr = *sc->sc_tba; 921 sc->sc_tbc --; 922 sc->sc_tba ++; 923 924 splx(s); 925 return; 926 927 stopped: 928 /* Disable transmit completion interrupts if necessary. */ 929 if (ISSET(sc->sc_imra, IA_TRDY)) { 930 CLR(sc->sc_imra, IA_TRDY|IA_TERR); 931 single_inst_bclr_b(MFP->mf_imra, IA_TRDY|IA_TERR); 932 } 933 out: 934 splx(s); 935 return; 936 } 937 938 /* 939 * Stop output on a line. 940 */ 941 void 942 serstop(tp, flag) 943 struct tty *tp; 944 int flag; 945 { 946 struct ser_softc *sc = ser_cd.cd_devs[SERUNIT(tp->t_dev)]; 947 int s; 948 949 s = splserial(); 950 if (ISSET(tp->t_state, TS_BUSY)) { 951 /* Stop transmitting at the next chunk. */ 952 sc->sc_tbc = 0; 953 sc->sc_heldtbc = 0; 954 if (!ISSET(tp->t_state, TS_TTSTOP)) 955 SET(tp->t_state, TS_FLUSH); 956 } 957 splx(s); 958 } 959 960 void 961 serdiag(arg) 962 void *arg; 963 { 964 struct ser_softc *sc = arg; 965 int overflows, floods; 966 int s; 967 968 s = splserial(); 969 overflows = sc->sc_overflows; 970 sc->sc_overflows = 0; 971 floods = sc->sc_floods; 972 sc->sc_floods = 0; 973 sc->sc_errors = 0; 974 splx(s); 975 976 log(LOG_WARNING, 977 "%s: %d silo overflow%s, %d ibuf flood%s\n", 978 sc->sc_dev.dv_xname, 979 overflows, overflows == 1 ? "" : "s", 980 floods, floods == 1 ? "" : "s"); 981 } 982 983 static void 984 serrxint(sc, tp) 985 struct ser_softc *sc; 986 struct tty *tp; 987 { 988 u_int get, cc, scc; 989 int code; 990 u_char rsr; 991 int s; 992 static int lsrmap[8] = { 993 0, TTY_PE, 994 TTY_FE, TTY_PE|TTY_FE, 995 TTY_FE, TTY_PE|TTY_FE, 996 TTY_FE, TTY_PE|TTY_FE 997 }; 998 999 get = sc->sc_rbget; 1000 scc = cc = RXBUFSIZE - sc->sc_rbavail; 1001 1002 if (cc == RXBUFSIZE) { 1003 sc->sc_floods++; 1004 if (sc->sc_errors++ == 0) 1005 timeout(serdiag, sc, 60 * hz); 1006 } 1007 1008 while (cc--) { 1009 rsr = sc->sc_lbuf[get]; 1010 if (ISSET(rsr, RSR_BREAK)) { 1011 #ifdef DDB 1012 if (ISSET(sc->sc_hwflags, SER_HW_CONSOLE)) 1013 Debugger(); 1014 #endif 1015 } 1016 else if (ISSET(rsr, RSR_OERR)) { 1017 sc->sc_overflows++; 1018 if (sc->sc_errors++ == 0) 1019 timeout(serdiag, sc, 60 * hz); 1020 } 1021 code = sc->sc_rbuf[get] | 1022 lsrmap[(rsr & (RSR_BREAK|RSR_FERR|RSR_PERR)) >> 3]; 1023 (*linesw[tp->t_line].l_rint)(code, tp); 1024 get = (get + 1) & RXBUFMASK; 1025 } 1026 1027 sc->sc_rbget = get; 1028 s = splserial(); 1029 sc->sc_rbavail += scc; 1030 /* 1031 * Buffers should be ok again, release possible block, but only if the 1032 * tty layer isn't blocking too. 1033 */ 1034 if (sc->sc_rx_blocked && !ISSET(tp->t_state, TS_TBLOCK)) { 1035 sc->sc_rx_blocked = 0; 1036 ser_hwiflow(sc, 0); 1037 } 1038 splx(s); 1039 } 1040 1041 static void 1042 sertxint(sc, tp) 1043 struct ser_softc *sc; 1044 struct tty *tp; 1045 { 1046 1047 CLR(tp->t_state, TS_BUSY); 1048 if (ISSET(tp->t_state, TS_FLUSH)) 1049 CLR(tp->t_state, TS_FLUSH); 1050 else 1051 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); 1052 (*linesw[tp->t_line].l_start)(tp); 1053 } 1054 1055 static void 1056 sermsrint(sc, tp) 1057 struct ser_softc *sc; 1058 struct tty *tp; 1059 { 1060 u_char msr, delta; 1061 int s; 1062 1063 s = splserial(); 1064 msr = sc->sc_msr; 1065 delta = sc->sc_msr_delta; 1066 sc->sc_msr_delta = 0; 1067 splx(s); 1068 1069 if (ISSET(delta, sc->sc_msr_dcd)) { 1070 /* 1071 * Inform the tty layer that carrier detect changed. 1072 */ 1073 (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MCR_DCD)); 1074 } 1075 1076 if (ISSET(delta, sc->sc_msr_cts)) { 1077 /* Block or unblock output according to flow control. */ 1078 if (ISSET(msr, sc->sc_msr_cts)) { 1079 sc->sc_tx_stopped = 0; 1080 (*linesw[tp->t_line].l_start)(tp); 1081 } else { 1082 sc->sc_tx_stopped = 1; 1083 serstop(tp, 0); 1084 } 1085 } 1086 1087 #ifdef SER_DEBUG 1088 serstatus(sc, "sermsrint"); 1089 #endif 1090 } 1091 1092 void 1093 sersoft(arg) 1094 void *arg; 1095 { 1096 struct ser_softc *sc = arg; 1097 struct tty *tp; 1098 1099 ser_softintr_scheduled = 0; 1100 1101 tp = sc->sc_tty; 1102 if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN | TS_WOPEN)) 1103 return; 1104 1105 if (sc->sc_rx_ready) { 1106 sc->sc_rx_ready = 0; 1107 serrxint(sc, tp); 1108 } 1109 1110 if (sc->sc_st_check) { 1111 sc->sc_st_check = 0; 1112 sermsrint(sc, tp); 1113 } 1114 1115 if (sc->sc_tx_done) { 1116 sc->sc_tx_done = 0; 1117 sertxint(sc, tp); 1118 } 1119 } 1120 1121 int 1122 sermintr(arg) 1123 void *arg; 1124 { 1125 struct ser_softc *sc = arg; 1126 u_char msr, delta; 1127 1128 msr = ~MFP->mf_gpip; 1129 delta = msr ^ sc->sc_msr; 1130 sc->sc_msr = sc->sc_msr & ~(MCR_CTS|MCR_DCD|MCR_RI); 1131 sc->sc_msr |= msr & (MCR_CTS|MCR_DCD|MCR_RI); 1132 1133 if (ISSET(delta, sc->sc_msr_mask)) { 1134 sc->sc_msr_delta |= delta; 1135 1136 /* 1137 * Stop output immediately if we lose the output 1138 * flow control signal or carrier detect. 1139 */ 1140 if (ISSET(~msr, sc->sc_msr_mask)) { 1141 sc->sc_tbc = 0; 1142 sc->sc_heldtbc = 0; 1143 #ifdef SER_DEBUG 1144 serstatus(sc, "sermintr "); 1145 #endif 1146 } 1147 1148 sc->sc_st_check = 1; 1149 } 1150 if (!ser_softintr_scheduled) 1151 add_sicallback((si_farg)sersoft, sc, 0); 1152 return 1; 1153 } 1154 1155 int 1156 sertrintr(arg) 1157 void *arg; 1158 { 1159 struct ser_softc *sc = arg; 1160 u_int put, cc; 1161 u_char rsr, tsr; 1162 1163 put = sc->sc_rbput; 1164 cc = sc->sc_rbavail; 1165 1166 rsr = MFP->mf_rsr; 1167 if (ISSET(rsr, RSR_BFULL|RSR_BREAK)) { 1168 for (; ISSET(rsr, RSR_BFULL|RSR_BREAK) && cc > 0; cc--) { 1169 sc->sc_rbuf[put] = MFP->mf_udr; 1170 sc->sc_lbuf[put] = rsr; 1171 put = (put + 1) & RXBUFMASK; 1172 if ((rsr & RSR_BREAK) && (MFP->mf_rsr & RSR_BREAK)) 1173 rsr = 0; 1174 else rsr = MFP->mf_rsr; 1175 } 1176 /* 1177 * Current string of incoming characters ended because 1178 * no more data was available. Schedule a receive event 1179 * if any data was received. Drop any characters that 1180 * we couldn't handle. 1181 */ 1182 sc->sc_rbput = put; 1183 sc->sc_rbavail = cc; 1184 sc->sc_rx_ready = 1; 1185 /* 1186 * See if we are in danger of overflowing a buffer. If 1187 * so, use hardware flow control to ease the pressure. 1188 */ 1189 if (sc->sc_rx_blocked == 0 && 1190 cc < sc->sc_r_hiwat) { 1191 sc->sc_rx_blocked = 1; 1192 ser_hwiflow(sc, 1); 1193 } 1194 /* 1195 * If we're out of space, throw away any further input. 1196 */ 1197 if (!cc) { 1198 while (ISSET(rsr, RSR_BFULL|RSR_BREAK)) { 1199 rsr = MFP->mf_udr; 1200 rsr = MFP->mf_rsr; 1201 } 1202 } 1203 } 1204 1205 /* 1206 * Done handling any receive interrupts. See if data can be 1207 * transmitted as well. Schedule tx done event if no data left 1208 * and tty was marked busy. 1209 */ 1210 tsr = MFP->mf_tsr; 1211 if (ISSET(tsr, TSR_BE)) { 1212 /* 1213 * If we've delayed a parameter change, do it now, and restart 1214 * output. 1215 */ 1216 if (sc->sc_heldchange) { 1217 ser_loadchannelregs(sc); 1218 sc->sc_heldchange = 0; 1219 sc->sc_tbc = sc->sc_heldtbc; 1220 sc->sc_heldtbc = 0; 1221 } 1222 /* Output the next character, if any. */ 1223 if (sc->sc_tbc > 0) { 1224 MFP->mf_udr = *sc->sc_tba; 1225 sc->sc_tbc --; 1226 sc->sc_tba ++; 1227 } else if (sc->sc_tx_busy) { 1228 sc->sc_tx_busy = 0; 1229 sc->sc_tx_done = 1; 1230 } 1231 } 1232 1233 if (!ser_softintr_scheduled) 1234 add_sicallback((si_farg)sersoft, sc, 0); 1235 return 1; 1236 } 1237 1238 static int 1239 serspeed(speed) 1240 long speed; 1241 { 1242 #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ 1243 1244 int div, x, err; 1245 1246 if (speed <= 0) 1247 return (-1); 1248 1249 for (div = 4; div <= 64; div *= 4) { 1250 x = divrnd((SER_FREQ / div), speed); 1251 1252 /* 1253 * The value must fit in the timer-d dataregister. If 1254 * not, try another delay-mode. 1255 */ 1256 if ((x/2) > 255) 1257 continue; 1258 1259 /* 1260 * Baudrate to high for the interface or cannot be made 1261 * within tolerance. 1262 */ 1263 if (x <= 0) 1264 return (-1); 1265 1266 err = divrnd((SER_FREQ / div) * 1000, speed * x) - 1000; 1267 if (err < 0) 1268 err = -err; 1269 if (err > SER_TOLERANCE) 1270 continue; 1271 1272 /* 1273 * Translate 'div' to delay-code 1274 */ 1275 if (div == 4) 1276 div = 1; 1277 else if (div == 16) 1278 div = 3; 1279 else if (div == 64) 1280 div = 5; 1281 1282 return ((x/2) | (div << 8)); 1283 } 1284 return (-1); 1285 1286 #undef divrnd(n, q) 1287 } 1288 1289 /* 1290 * Following are all routines needed for SER to act as console 1291 */ 1292 #include <dev/cons.h> 1293 1294 void 1295 sercnprobe(cp) 1296 struct consdev *cp; 1297 { 1298 /* 1299 * Activate serial console when DCD present... 1300 */ 1301 if (MFP->mf_gpip & MCR_DCD) { 1302 cp->cn_pri = CN_DEAD; 1303 return; 1304 } 1305 for (sermajor = 0; sermajor < nchrdev; sermajor++) 1306 if (cdevsw[sermajor].d_open == seropen) 1307 break; 1308 1309 /* initialize required fields */ 1310 cp->cn_dev = makedev(sermajor, 0); /* XXX: LWP What unit? */ 1311 #ifdef SERCONSOLE 1312 cp->cn_pri = CN_REMOTE; /* Force a serial port console */ 1313 #else 1314 cp->cn_pri = CN_NORMAL; 1315 #endif 1316 } 1317 1318 void 1319 sercninit(cp) 1320 struct consdev *cp; 1321 { 1322 serinitcons(CONSBAUD); 1323 } 1324 1325 /* 1326 * Initialize UART to known state. 1327 */ 1328 void 1329 serinit(baud) 1330 int baud; 1331 { 1332 int ospeed = serspeed(baud); 1333 1334 MFP->mf_ucr = UCR_CLKDIV|UCR_8BITS|UCR_STOPB1; 1335 MFP->mf_rsr = RSR_ENAB; 1336 MFP->mf_tsr = TSR_ENAB; 1337 1338 single_inst_bclr_b(MFP->mf_tcdcr, 0x07); 1339 MFP->mf_tddr = ospeed; 1340 single_inst_bset_b(MFP->mf_tcdcr, (ospeed >> 8) & 0x0f); 1341 } 1342 1343 /* 1344 * Set UART for console use. Do normal init, then enable interrupts. 1345 */ 1346 void 1347 serinitcons(baud) 1348 int baud; 1349 { 1350 serinit(baud); 1351 1352 /* Set rts/dtr */ 1353 ym2149_rts(0); 1354 ym2149_dtr(0); 1355 1356 single_inst_bset_b(MFP->mf_imra, (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR)); 1357 } 1358 1359 int 1360 sercngetc(dev) 1361 dev_t dev; 1362 { 1363 u_char stat, c; 1364 int s; 1365 1366 s = splserial(); 1367 while (!ISSET(stat = MFP->mf_rsr, RSR_BFULL)) { 1368 if (!ISSET(stat, RSR_ENAB)) /* XXX */ 1369 MFP->mf_rsr |= RSR_ENAB; 1370 if (stat & (RSR_FERR|RSR_PERR|RSR_OERR)) 1371 c = MFP->mf_udr; 1372 } 1373 c = MFP->mf_udr; 1374 splx(s); 1375 return c; 1376 } 1377 1378 u_int s_imra; 1379 u_int s_stat1, s_stat2, s_stat3; 1380 void 1381 sercnputc(dev, c) 1382 dev_t dev; 1383 int c; 1384 { 1385 int timo; 1386 u_char stat, imra; 1387 1388 /* Mask serial interrupts */ 1389 imra = MFP->mf_imra & (IA_RRDY|IA_RERR|IA_TRDY|IA_TERR); 1390 single_inst_bclr_b(MFP->mf_imra, imra); 1391 s_imra = imra; 1392 1393 /* wait for any pending transmission to finish */ 1394 timo = 50000; 1395 s_stat1 = MFP->mf_tsr; 1396 while (!ISSET(stat = MFP->mf_tsr, TSR_BE) && --timo) 1397 ; 1398 MFP->mf_udr = c; 1399 /* wait for this transmission to complete */ 1400 timo = 1500000; 1401 s_stat2 = MFP->mf_tsr; 1402 while (!ISSET(stat = MFP->mf_tsr, TSR_BE) && --timo) 1403 ; 1404 1405 s_stat3 = MFP->mf_tsr; 1406 /* Clear pending serial interrupts and re-enable */ 1407 single_inst_bclr_b(MFP->mf_ipra, imra); 1408 single_inst_bset_b(MFP->mf_imra, imra); 1409 } 1410 1411 void 1412 sercnpollc(dev, on) 1413 dev_t dev; 1414 int on; 1415 { 1416 1417 } 1418