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