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