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