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