1 /* $NetBSD: epcom.c,v 1.32 2020/11/20 18:03:52 thorpej Exp $ */ 2 /* 3 * Copyright (c) 1998, 1999, 2001, 2002, 2004 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Jesse Off 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Ichiro FUKUHARA and Naoto Shimazaki. 11 * 12 * This code is derived from software contributed to The NetBSD Foundation 13 * by IWAMOTO Toshihiro. 14 * 15 * This code is derived from software contributed to The NetBSD Foundation 16 * by Charles M. Hannum. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * Copyright (c) 1991 The Regents of the University of California. 42 * All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 * 68 * @(#)com.c 7.5 (Berkeley) 5/16/91 69 */ 70 71 /* 72 * TODO: hardware flow control 73 */ 74 75 #include <sys/cdefs.h> 76 __KERNEL_RCSID(0, "$NetBSD: epcom.c,v 1.32 2020/11/20 18:03:52 thorpej Exp $"); 77 78 #include "opt_ddb.h" 79 #include "opt_kgdb.h" 80 #include "epcom.h" 81 82 #ifdef RND_COM 83 #include <sys/rndsource.h> 84 #endif 85 86 /* 87 * Override cnmagic(9) macro before including <sys/systm.h>. 88 * We need to know if cn_check_magic triggered debugger, so set a flag. 89 * Callers of cn_check_magic must declare int cn_trapped = 0; 90 * XXX: this is *ugly*! 91 */ 92 #define cn_trap() \ 93 do { \ 94 console_debugger(); \ 95 cn_trapped = 1; \ 96 } while (/* CONSTCOND */ 0) 97 98 99 #include <sys/param.h> 100 #include <sys/systm.h> 101 #include <sys/types.h> 102 #include <sys/conf.h> 103 #include <sys/file.h> 104 #include <sys/device.h> 105 #include <sys/kernel.h> 106 #include <sys/kmem.h> 107 #include <sys/tty.h> 108 #include <sys/uio.h> 109 #include <sys/vnode.h> 110 #include <sys/kauth.h> 111 112 #include <machine/intr.h> 113 #include <sys/bus.h> 114 115 #include <arm/ep93xx/epcomreg.h> 116 #include <arm/ep93xx/epcomvar.h> 117 #include <arm/ep93xx/ep93xxreg.h> 118 #include <arm/ep93xx/ep93xxvar.h> 119 120 #include <dev/cons.h> 121 122 static int epcomparam(struct tty *, struct termios *); 123 static void epcomstart(struct tty *); 124 static int epcomhwiflow(struct tty *, int); 125 126 static u_int cflag2lcrhi(tcflag_t); 127 static void epcom_iflush(struct epcom_softc *); 128 static void epcom_set(struct epcom_softc *); 129 130 int epcomcngetc(dev_t); 131 void epcomcnputc(dev_t, int); 132 void epcomcnpollc(dev_t, int); 133 134 static void epcomsoft(void* arg); 135 inline static void epcom_txsoft(struct epcom_softc *, struct tty *); 136 inline static void epcom_rxsoft(struct epcom_softc *, struct tty *); 137 138 void epcomcnprobe(struct consdev *); 139 void epcomcninit(struct consdev *); 140 141 static struct epcom_cons_softc { 142 bus_space_tag_t sc_iot; 143 bus_space_handle_t sc_ioh; 144 bus_addr_t sc_hwbase; 145 int sc_ospeed; 146 tcflag_t sc_cflag; 147 int sc_attached; 148 } epcomcn_sc; 149 150 static struct cnm_state epcom_cnm_state; 151 152 extern struct cfdriver epcom_cd; 153 154 dev_type_open(epcomopen); 155 dev_type_close(epcomclose); 156 dev_type_read(epcomread); 157 dev_type_write(epcomwrite); 158 dev_type_ioctl(epcomioctl); 159 dev_type_stop(epcomstop); 160 dev_type_tty(epcomtty); 161 dev_type_poll(epcompoll); 162 163 const struct cdevsw epcom_cdevsw = { 164 .d_open = epcomopen, 165 .d_close = epcomclose, 166 .d_read = epcomread, 167 .d_write = epcomwrite, 168 .d_ioctl = epcomioctl, 169 .d_stop = epcomstop, 170 .d_tty = epcomtty, 171 .d_poll = epcompoll, 172 .d_mmap = nommap, 173 .d_kqfilter = ttykqfilter, 174 .d_discard = nodiscard, 175 .d_flag = D_TTY 176 }; 177 178 struct consdev epcomcons = { 179 NULL, NULL, epcomcngetc, epcomcnputc, epcomcnpollc, NULL, 180 NULL, NULL, NODEV, CN_NORMAL 181 }; 182 183 #ifndef DEFAULT_COMSPEED 184 #define DEFAULT_COMSPEED 115200 185 #endif 186 187 #define COMUNIT(x) TTUNIT(x) 188 #define COMDIALOUT(x) TTDIALOUT(x) 189 190 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \ 191 device_is_active((sc)->sc_dev)) 192 193 void 194 epcom_attach_subr(struct epcom_softc *sc) 195 { 196 struct tty *tp; 197 198 if (sc->sc_iot == epcomcn_sc.sc_iot 199 && sc->sc_hwbase == epcomcn_sc.sc_hwbase) { 200 epcomcn_sc.sc_attached = 1; 201 sc->sc_lcrlo = EPCOMSPEED2BRD(epcomcn_sc.sc_ospeed) & 0xff; 202 sc->sc_lcrmid = EPCOMSPEED2BRD(epcomcn_sc.sc_ospeed) >> 8; 203 204 /* Make sure the console is always "hardwired". */ 205 delay(10000); /* wait for output to finish */ 206 SET(sc->sc_hwflags, COM_HW_CONSOLE); 207 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR); 208 } 209 210 tp = tty_alloc(); 211 tp->t_oproc = epcomstart; 212 tp->t_param = epcomparam; 213 tp->t_hwiflow = epcomhwiflow; 214 215 sc->sc_tty = tp; 216 sc->sc_rbuf = kmem_alloc(EPCOM_RING_SIZE << 1, KM_SLEEP); 217 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 218 sc->sc_rbavail = EPCOM_RING_SIZE; 219 sc->sc_ebuf = sc->sc_rbuf + (EPCOM_RING_SIZE << 1); 220 sc->sc_tbc = 0; 221 222 sc->sc_lcrlo = EPCOMSPEED2BRD(DEFAULT_COMSPEED) & 0xff; 223 sc->sc_lcrmid = EPCOMSPEED2BRD(DEFAULT_COMSPEED) >> 8; 224 sc->sc_lcrhi = cflag2lcrhi(CS8); /* 8N1 */ 225 226 tty_attach(tp); 227 228 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 229 int maj; 230 231 /* locate the major number */ 232 maj = cdevsw_lookup_major(&epcom_cdevsw); 233 234 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev)); 235 236 aprint_normal("%s: console\n", device_xname(sc->sc_dev)); 237 } 238 239 sc->sc_si = softint_establish(SOFTINT_SERIAL, epcomsoft, sc); 240 241 #ifdef RND_COM 242 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 243 RND_TYPE_TTY, RND_FLAG_DEFAULT); 244 #endif 245 246 /* if there are no enable/disable functions, assume the device 247 is always enabled */ 248 if (!sc->enable) 249 sc->enabled = 1; 250 251 /* XXX configure register */ 252 /* xxx_config(sc) */ 253 254 SET(sc->sc_hwflags, COM_HW_DEV_OK); 255 } 256 257 static int 258 epcomparam(struct tty *tp, struct termios *t) 259 { 260 struct epcom_softc *sc 261 = device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev)); 262 int s; 263 264 if (COM_ISALIVE(sc) == 0) 265 return (EIO); 266 267 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 268 return (EINVAL); 269 270 /* 271 * For the console, always force CLOCAL and !HUPCL, so that the port 272 * is always active. 273 */ 274 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 275 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 276 SET(t->c_cflag, CLOCAL); 277 CLR(t->c_cflag, HUPCL); 278 } 279 280 /* 281 * If there were no changes, don't do anything. This avoids dropping 282 * input and improves performance when all we did was frob things like 283 * VMIN and VTIME. 284 */ 285 if (tp->t_ospeed == t->c_ospeed && 286 tp->t_cflag == t->c_cflag) 287 return (0); 288 289 s = splserial(); 290 291 sc->sc_lcrhi = cflag2lcrhi(t->c_cflag); 292 sc->sc_lcrlo = EPCOMSPEED2BRD(t->c_ospeed) & 0xff; 293 sc->sc_lcrmid = EPCOMSPEED2BRD(t->c_ospeed) >> 8; 294 295 /* And copy to tty. */ 296 tp->t_ispeed = 0; 297 tp->t_ospeed = t->c_ospeed; 298 tp->t_cflag = t->c_cflag; 299 epcom_set(sc); 300 301 splx(s); 302 303 /* 304 * Update the tty layer's idea of the carrier bit. 305 * We tell tty the carrier is always on. 306 */ 307 (void) (*tp->t_linesw->l_modem)(tp, 1); 308 309 #ifdef COM_DEBUG 310 if (com_debug) 311 comstatus(sc, "comparam "); 312 #endif 313 314 if (!ISSET(t->c_cflag, CHWFLOW)) { 315 if (sc->sc_tx_stopped) { 316 sc->sc_tx_stopped = 0; 317 epcomstart(tp); 318 } 319 } 320 321 return (0); 322 } 323 324 static int 325 epcomhwiflow(struct tty *tp, int block) 326 { 327 return (0); 328 } 329 330 static void 331 epcom_filltx(struct epcom_softc *sc) 332 { 333 bus_space_tag_t iot = sc->sc_iot; 334 bus_space_handle_t ioh = sc->sc_ioh; 335 int n; 336 337 n = 0; 338 while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFF) == 0) { 339 if (n >= sc->sc_tbc) 340 break; 341 bus_space_write_4(iot, ioh, EPCOM_Data, 342 0xff & *(sc->sc_tba + n)); 343 n++; 344 } 345 sc->sc_tbc -= n; 346 sc->sc_tba += n; 347 } 348 349 static void 350 epcomstart(struct tty *tp) 351 { 352 struct epcom_softc *sc 353 = device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev)); 354 int s; 355 356 if (COM_ISALIVE(sc) == 0) 357 return; 358 359 s = spltty(); 360 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 361 goto out; 362 if (sc->sc_tx_stopped) 363 goto out; 364 if (!ttypull(tp)) 365 goto out; 366 367 /* Grab the first contiguous region of buffer space. */ 368 { 369 u_char *tba; 370 int tbc; 371 372 tba = tp->t_outq.c_cf; 373 tbc = ndqb(&tp->t_outq, 0); 374 375 (void)splserial(); 376 377 sc->sc_tba = tba; 378 sc->sc_tbc = tbc; 379 } 380 381 SET(tp->t_state, TS_BUSY); 382 sc->sc_tx_busy = 1; 383 384 /* Output the first chunk of the contiguous buffer. */ 385 epcom_filltx(sc); 386 387 if (!ISSET(sc->sc_ctrl, Ctrl_TIE)) { 388 SET(sc->sc_ctrl, Ctrl_TIE); 389 epcom_set(sc); 390 } 391 392 out: 393 splx(s); 394 return; 395 } 396 397 static void 398 epcom_break(struct epcom_softc *sc, int onoff) 399 { 400 if (onoff) 401 SET(sc->sc_lcrhi, LinCtrlHigh_BRK); 402 else 403 CLR(sc->sc_lcrhi, LinCtrlHigh_BRK); 404 epcom_set(sc); 405 } 406 407 static void 408 epcom_shutdown(struct epcom_softc *sc) 409 { 410 int s; 411 412 s = splserial(); 413 414 /* Turn off interrupts. */ 415 CLR(sc->sc_ctrl, (Ctrl_TIE|Ctrl_RTIE|Ctrl_RIE)); 416 417 /* Clear any break condition set with TIOCSBRK. */ 418 epcom_break(sc, 0); 419 epcom_set(sc); 420 421 if (sc->disable) { 422 #ifdef DIAGNOSTIC 423 if (!sc->enabled) 424 panic("epcom_shutdown: not enabled?"); 425 #endif 426 (*sc->disable)(sc); 427 sc->enabled = 0; 428 } 429 splx(s); 430 } 431 432 int 433 epcomopen(dev_t dev, int flag, int mode, struct lwp *l) 434 { 435 struct epcom_softc *sc; 436 struct tty *tp; 437 int s, s2; 438 int error; 439 440 sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 441 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) || 442 sc->sc_rbuf == NULL) 443 return (ENXIO); 444 445 if (!device_is_active(sc->sc_dev)) 446 return (ENXIO); 447 448 #ifdef KGDB 449 /* 450 * If this is the kgdb port, no other use is permitted. 451 */ 452 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 453 return (EBUSY); 454 #endif 455 456 tp = sc->sc_tty; 457 458 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 459 return (EBUSY); 460 461 s = spltty(); 462 463 /* 464 * Do the following iff this is a first open. 465 */ 466 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 467 struct termios t; 468 469 tp->t_dev = dev; 470 471 s2 = splserial(); 472 473 if (sc->enable) { 474 if ((*sc->enable)(sc)) { 475 splx(s2); 476 splx(s); 477 printf("%s: device enable failed\n", 478 device_xname(sc->sc_dev)); 479 return (EIO); 480 } 481 sc->enabled = 1; 482 #if 0 483 /* XXXXXXXXXXXXXXX */ 484 com_config(sc); 485 #endif 486 } 487 488 /* Turn on interrupts. */ 489 SET(sc->sc_ctrl, (Ctrl_UARTE|Ctrl_RIE|Ctrl_RTIE)); 490 epcom_set(sc); 491 492 #if 0 493 /* Fetch the current modem control status, needed later. */ 494 sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr); 495 496 /* Clear PPS capture state on first open. */ 497 sc->sc_ppsmask = 0; 498 sc->ppsparam.mode = 0; 499 #endif 500 501 splx(s2); 502 503 /* 504 * Initialize the termios status to the defaults. Add in the 505 * sticky bits from TIOCSFLAGS. 506 */ 507 t.c_ispeed = 0; 508 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 509 t.c_ospeed = epcomcn_sc.sc_ospeed; 510 t.c_cflag = epcomcn_sc.sc_cflag; 511 } else { 512 t.c_ospeed = TTYDEF_SPEED; 513 t.c_cflag = TTYDEF_CFLAG; 514 } 515 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 516 SET(t.c_cflag, CLOCAL); 517 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 518 SET(t.c_cflag, CRTSCTS); 519 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 520 SET(t.c_cflag, MDMBUF); 521 /* Make sure epcomparam() will do something. */ 522 tp->t_ospeed = 0; 523 (void) epcomparam(tp, &t); 524 tp->t_iflag = TTYDEF_IFLAG; 525 tp->t_oflag = TTYDEF_OFLAG; 526 tp->t_lflag = TTYDEF_LFLAG; 527 ttychars(tp); 528 ttsetwater(tp); 529 530 s2 = splserial(); 531 532 /* Clear the input ring, and unblock. */ 533 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 534 sc->sc_rbavail = EPCOM_RING_SIZE; 535 epcom_iflush(sc); 536 CLR(sc->sc_rx_flags, RX_ANY_BLOCK); 537 538 #ifdef COM_DEBUG 539 if (epcom_debug) 540 comstatus(sc, "epcomopen "); 541 #endif 542 543 splx(s2); 544 } 545 546 splx(s); 547 548 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 549 if (error) 550 goto bad; 551 552 error = (*tp->t_linesw->l_open)(dev, tp); 553 if (error) 554 goto bad; 555 556 return (0); 557 558 bad: 559 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 560 /* 561 * We failed to open the device, and nobody else had it opened. 562 * Clean up the state as appropriate. 563 */ 564 epcom_shutdown(sc); 565 } 566 567 return (error); 568 } 569 570 int 571 epcomclose(dev_t dev, int flag, int mode, struct lwp *l) 572 { 573 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 574 struct tty *tp = sc->sc_tty; 575 576 /* XXX This is for cons.c. */ 577 if (!ISSET(tp->t_state, TS_ISOPEN)) 578 return (0); 579 580 (*tp->t_linesw->l_close)(tp, flag); 581 ttyclose(tp); 582 583 if (COM_ISALIVE(sc) == 0) 584 return (0); 585 586 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 587 /* 588 * Although we got a last close, the device may still be in 589 * use; e.g. if this was the dialout node, and there are still 590 * processes waiting for carrier on the non-dialout node. 591 */ 592 epcom_shutdown(sc); 593 } 594 595 return (0); 596 } 597 598 int 599 epcomread(dev_t dev, struct uio *uio, int flag) 600 { 601 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 602 struct tty *tp = sc->sc_tty; 603 604 if (COM_ISALIVE(sc) == 0) 605 return (EIO); 606 607 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 608 } 609 610 int 611 epcomwrite(dev_t dev, struct uio *uio, int flag) 612 { 613 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 614 struct tty *tp = sc->sc_tty; 615 616 if (COM_ISALIVE(sc) == 0) 617 return (EIO); 618 619 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 620 } 621 622 int 623 epcompoll(dev_t dev, int events, struct lwp *l) 624 { 625 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 626 struct tty *tp = sc->sc_tty; 627 628 if (COM_ISALIVE(sc) == 0) 629 return (EIO); 630 631 return ((*tp->t_linesw->l_poll)(tp, events, l)); 632 } 633 634 struct tty * 635 epcomtty(dev_t dev) 636 { 637 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 638 struct tty *tp = sc->sc_tty; 639 640 return (tp); 641 } 642 643 int 644 epcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 645 { 646 struct epcom_softc *sc = device_lookup_private(&epcom_cd, COMUNIT(dev)); 647 struct tty *tp = sc->sc_tty; 648 int error; 649 int s; 650 651 if (COM_ISALIVE(sc) == 0) 652 return (EIO); 653 654 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 655 if (error != EPASSTHROUGH) 656 return (error); 657 658 error = ttioctl(tp, cmd, data, flag, l); 659 if (error != EPASSTHROUGH) 660 return (error); 661 662 error = 0; 663 664 s = splserial(); 665 666 switch (cmd) { 667 case TIOCSBRK: 668 epcom_break(sc, 1); 669 break; 670 671 case TIOCCBRK: 672 epcom_break(sc, 0); 673 break; 674 675 case TIOCGFLAGS: 676 *(int *)data = sc->sc_swflags; 677 break; 678 679 case TIOCSFLAGS: 680 error = kauth_authorize_device_tty(l->l_cred, 681 KAUTH_DEVICE_TTY_PRIVSET, tp); 682 if (error) 683 break; 684 sc->sc_swflags = *(int *)data; 685 break; 686 687 default: 688 error = EPASSTHROUGH; 689 break; 690 } 691 692 splx(s); 693 694 return (error); 695 } 696 697 /* 698 * Stop output on a line. 699 */ 700 void 701 epcomstop(struct tty *tp, int flag) 702 { 703 struct epcom_softc *sc 704 = device_lookup_private(&epcom_cd, COMUNIT(tp->t_dev)); 705 int s; 706 707 s = splserial(); 708 if (ISSET(tp->t_state, TS_BUSY)) { 709 /* Stop transmitting at the next chunk. */ 710 sc->sc_tbc = 0; 711 if (!ISSET(tp->t_state, TS_TTSTOP)) 712 SET(tp->t_state, TS_FLUSH); 713 } 714 splx(s); 715 } 716 717 static u_int 718 cflag2lcrhi(tcflag_t cflag) 719 { 720 u_int lcrhi; 721 722 switch (cflag & CSIZE) { 723 case CS7: 724 lcrhi = 0x40; 725 break; 726 case CS6: 727 lcrhi = 0x20; 728 break; 729 case CS8: 730 default: 731 lcrhi = 0x60; 732 break; 733 } 734 lcrhi |= (cflag & PARENB) ? LinCtrlHigh_PEN : 0; 735 lcrhi |= (cflag & PARODD) ? 0 : LinCtrlHigh_EPS; 736 lcrhi |= (cflag & CSTOPB) ? LinCtrlHigh_STP2 : 0; 737 lcrhi |= LinCtrlHigh_FEN; /* FIFO always enabled */ 738 739 return (lcrhi); 740 } 741 742 static void 743 epcom_iflush(struct epcom_softc *sc) 744 { 745 bus_space_tag_t iot = sc->sc_iot; 746 bus_space_handle_t ioh = sc->sc_ioh; 747 #ifdef DIAGNOSTIC 748 int reg; 749 #endif 750 int timo; 751 752 #ifdef DIAGNOSTIC 753 reg = 0xffff; 754 #endif 755 timo = 50000; 756 /* flush any pending I/O */ 757 while ((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_RXFE) == 0 758 && --timo) 759 #ifdef DIAGNOSTIC 760 reg = 761 #else 762 (void) 763 #endif 764 bus_space_read_4(iot, ioh, EPCOM_Data); 765 #ifdef DIAGNOSTIC 766 if (!timo) 767 printf("%s: com_iflush timeout %02x\n", device_xname(sc->sc_dev), 768 reg); 769 #endif 770 } 771 772 static void 773 epcom_set(struct epcom_softc *sc) 774 { 775 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlLow, 776 sc->sc_lcrlo); 777 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlMid, 778 sc->sc_lcrmid); 779 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_LinCtrlHigh, 780 sc->sc_lcrhi); 781 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EPCOM_Ctrl, 782 sc->sc_ctrl); 783 } 784 785 int 786 epcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh, 787 int ospeed, tcflag_t cflag) 788 { 789 u_int lcrlo, lcrmid, lcrhi, ctrl, pwrcnt; 790 bus_space_handle_t syscon_ioh; 791 792 cn_tab = &epcomcons; 793 cn_init_magic(&epcom_cnm_state); 794 cn_set_magic("\047\001"); 795 796 epcomcn_sc.sc_iot = iot; 797 epcomcn_sc.sc_ioh = ioh; 798 epcomcn_sc.sc_hwbase = iobase; 799 epcomcn_sc.sc_ospeed = ospeed; 800 epcomcn_sc.sc_cflag = cflag; 801 802 lcrhi = cflag2lcrhi(cflag); 803 lcrlo = EPCOMSPEED2BRD(ospeed) & 0xff; 804 lcrmid = EPCOMSPEED2BRD(ospeed) >> 8; 805 ctrl = Ctrl_UARTE; 806 807 bus_space_map(iot, EP93XX_APB_HWBASE + EP93XX_APB_SYSCON, 808 EP93XX_APB_SYSCON_SIZE, 0, &syscon_ioh); 809 pwrcnt = bus_space_read_4(iot, syscon_ioh, EP93XX_SYSCON_PwrCnt); 810 pwrcnt &= ~(PwrCnt_UARTBAUD); 811 bus_space_write_4(iot, syscon_ioh, EP93XX_SYSCON_PwrCnt, pwrcnt); 812 bus_space_unmap(iot, syscon_ioh, EP93XX_APB_SYSCON_SIZE); 813 814 bus_space_write_4(iot, ioh, EPCOM_LinCtrlLow, lcrlo); 815 bus_space_write_4(iot, ioh, EPCOM_LinCtrlMid, lcrmid); 816 bus_space_write_4(iot, ioh, EPCOM_LinCtrlHigh, lcrhi); 817 bus_space_write_4(iot, ioh, EPCOM_Ctrl, ctrl); 818 819 return (0); 820 } 821 822 void 823 epcomcnprobe(struct consdev *cp) 824 { 825 cp->cn_pri = CN_REMOTE; 826 } 827 828 void 829 epcomcnpollc(dev_t dev, int on) 830 { 831 } 832 833 void 834 epcomcnputc(dev_t dev, int c) 835 { 836 int s; 837 bus_space_tag_t iot = epcomcn_sc.sc_iot; 838 bus_space_handle_t ioh = epcomcn_sc.sc_ioh; 839 840 s = splserial(); 841 842 while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFF) != 0) 843 ; 844 845 bus_space_write_4(iot, ioh, EPCOM_Data, c); 846 847 #ifdef DEBUG 848 if (c == '\r') { 849 while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_TXFE) == 0) 850 ; 851 } 852 #endif 853 854 splx(s); 855 } 856 857 int 858 epcomcngetc(dev_t dev) 859 { 860 int c, sts; 861 int s; 862 bus_space_tag_t iot = epcomcn_sc.sc_iot; 863 bus_space_handle_t ioh = epcomcn_sc.sc_ioh; 864 865 s = splserial(); 866 867 while((bus_space_read_4(iot, ioh, EPCOM_Flag) & Flag_RXFE) != 0) 868 ; 869 870 c = bus_space_read_4(iot, ioh, EPCOM_Data); 871 sts = bus_space_read_4(iot, ioh, EPCOM_RXSts); 872 if (ISSET(sts, RXSts_BE)) c = CNC_BREAK; 873 #ifdef DDB 874 extern int db_active; 875 if (!db_active) 876 #endif 877 { 878 int cn_trapped __unused = 0; 879 880 cn_check_magic(dev, c, epcom_cnm_state); 881 } 882 c &= 0xff; 883 splx(s); 884 885 return (c); 886 } 887 888 inline static void 889 epcom_txsoft(struct epcom_softc *sc, struct tty *tp) 890 { 891 CLR(tp->t_state, TS_BUSY); 892 if (ISSET(tp->t_state, TS_FLUSH)) 893 CLR(tp->t_state, TS_FLUSH); 894 else 895 ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf)); 896 (*tp->t_linesw->l_start)(tp); 897 } 898 899 inline static void 900 epcom_rxsoft(struct epcom_softc *sc, struct tty *tp) 901 { 902 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint; 903 u_char *get, *end; 904 u_int cc, scc; 905 u_char sts; 906 int code; 907 int s; 908 909 end = sc->sc_ebuf; 910 get = sc->sc_rbget; 911 scc = cc = EPCOM_RING_SIZE - sc->sc_rbavail; 912 #if 0 913 if (cc == EPCOM_RING_SIZE) { 914 sc->sc_floods++; 915 if (sc->sc_errors++ == 0) 916 callout_reset(&sc->sc_diag_callout, 60 * hz, 917 comdiag, sc); 918 } 919 #endif 920 while (cc) { 921 code = get[0]; 922 sts = get[1]; 923 if (ISSET(sts, RXSts_OE | RXSts_FE | RXSts_PE | RXSts_BE)) { 924 #if 0 925 if (ISSET(lsr, DR_ROR)) { 926 sc->sc_overflows++; 927 if (sc->sc_errors++ == 0) 928 callout_reset(&sc->sc_diag_callout, 929 60 * hz, comdiag, sc); 930 } 931 #endif 932 if (ISSET(sts, (RXSts_FE|RXSts_BE))) 933 SET(code, TTY_FE); 934 if (ISSET(sts, RXSts_PE)) 935 SET(code, TTY_PE); 936 } 937 if ((*rint)(code, tp) == -1) { 938 /* 939 * The line discipline's buffer is out of space. 940 */ 941 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) { 942 /* 943 * We're either not using flow control, or the 944 * line discipline didn't tell us to block for 945 * some reason. Either way, we have no way to 946 * know when there's more space available, so 947 * just drop the rest of the data. 948 */ 949 get += cc << 1; 950 if (get >= end) 951 get -= EPCOM_RING_SIZE << 1; 952 cc = 0; 953 } else { 954 /* 955 * Don't schedule any more receive processing 956 * until the line discipline tells us there's 957 * space available (through comhwiflow()). 958 * Leave the rest of the data in the input 959 * buffer. 960 */ 961 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED); 962 } 963 break; 964 } 965 get += 2; 966 if (get >= end) 967 get = sc->sc_rbuf; 968 cc--; 969 } 970 971 if (cc != scc) { 972 sc->sc_rbget = get; 973 s = splserial(); 974 975 cc = sc->sc_rbavail += scc - cc; 976 /* Buffers should be ok again, release possible block. */ 977 if (cc >= 1) { 978 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { 979 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); 980 SET(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE)); 981 epcom_set(sc); 982 } 983 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) { 984 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED); 985 #if 0 986 com_hwiflow(sc); 987 #endif 988 } 989 } 990 splx(s); 991 } 992 } 993 994 static void 995 epcomsoft(void* arg) 996 { 997 struct epcom_softc *sc = arg; 998 999 if (COM_ISALIVE(sc) == 0) 1000 return; 1001 1002 if (sc->sc_rx_ready) { 1003 sc->sc_rx_ready = 0; 1004 epcom_rxsoft(sc, sc->sc_tty); 1005 } 1006 if (sc->sc_tx_done) { 1007 sc->sc_tx_done = 0; 1008 epcom_txsoft(sc, sc->sc_tty); 1009 } 1010 } 1011 1012 int 1013 epcomintr(void* arg) 1014 { 1015 struct epcom_softc *sc = arg; 1016 bus_space_tag_t iot = sc->sc_iot; 1017 bus_space_handle_t ioh = sc->sc_ioh; 1018 u_char *put, *end; 1019 u_int cc; 1020 u_int flagr; 1021 uint32_t c, csts; 1022 1023 (void) bus_space_read_4(iot, ioh, EPCOM_IntIDIntClr); 1024 1025 if (COM_ISALIVE(sc) == 0) 1026 panic("intr on disabled epcom"); 1027 1028 flagr = bus_space_read_4(iot, ioh, EPCOM_Flag); 1029 1030 end = sc->sc_ebuf; 1031 put = sc->sc_rbput; 1032 cc = sc->sc_rbavail; 1033 1034 if (!(ISSET(flagr, Flag_RXFE))) { 1035 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { 1036 while (cc > 0) { 1037 if (ISSET(flagr, Flag_RXFE)) 1038 break; 1039 c = bus_space_read_4(iot, ioh, EPCOM_Data); 1040 csts = bus_space_read_4(iot, ioh, EPCOM_RXSts); 1041 if (ISSET(csts, RXSts_BE)) { 1042 int cn_trapped = 0; 1043 1044 cn_check_magic(sc->sc_tty->t_dev, 1045 CNC_BREAK, epcom_cnm_state); 1046 if (cn_trapped) 1047 goto next; 1048 #if defined(KGDB) && !defined(DDB) 1049 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)){ 1050 kgdb_connect(1); 1051 goto next; 1052 } 1053 #endif 1054 } else { 1055 int cn_trapped = 0; 1056 1057 cn_check_magic(sc->sc_tty->t_dev, 1058 (c & 0xff), epcom_cnm_state); 1059 if (cn_trapped) 1060 goto next; 1061 } 1062 1063 1064 put[0] = c & 0xff; 1065 put[1] = csts & 0xf; 1066 put += 2; 1067 if (put >= end) 1068 put = sc->sc_rbuf; 1069 cc--; 1070 next: 1071 flagr = bus_space_read_4(iot, ioh, EPCOM_Flag); 1072 } 1073 1074 /* 1075 * Current string of incoming characters ended because 1076 * no more data was available or we ran out of space. 1077 * Schedule a receive event if any data was received. 1078 * If we're out of space, turn off receive interrupts. 1079 */ 1080 sc->sc_rbput = put; 1081 sc->sc_rbavail = cc; 1082 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) 1083 sc->sc_rx_ready = 1; 1084 1085 /* 1086 * See if we are in danger of overflowing a buffer. If 1087 * so, use hardware flow control to ease the pressure. 1088 */ 1089 1090 /* but epcom cannot. X-( */ 1091 1092 /* 1093 * If we're out of space, disable receive interrupts 1094 * until the queue has drained a bit. 1095 */ 1096 if (!cc) { 1097 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); 1098 CLR(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE)); 1099 epcom_set(sc); 1100 } 1101 } else { 1102 #ifdef DIAGNOSTIC 1103 panic("epcomintr: we shouldn't reach here"); 1104 #endif 1105 CLR(sc->sc_ctrl, (Ctrl_RIE|Ctrl_RTIE)); 1106 epcom_set(sc); 1107 } 1108 } 1109 1110 /* 1111 * Done handling any receive interrupts. See if data can be 1112 * transmitted as well. Schedule tx done event if no data left 1113 * and tty was marked busy. 1114 */ 1115 1116 if (!ISSET(flagr, Flag_TXFF) && sc->sc_tbc > 0) { 1117 /* Output the next chunk of the contiguous buffer, if any. */ 1118 epcom_filltx(sc); 1119 } else { 1120 /* Disable transmit completion interrupts if necessary. */ 1121 if (ISSET(sc->sc_ctrl, Ctrl_TIE)) { 1122 CLR(sc->sc_ctrl, Ctrl_TIE); 1123 epcom_set(sc); 1124 } 1125 if (sc->sc_tx_busy) { 1126 sc->sc_tx_busy = 0; 1127 sc->sc_tx_done = 1; 1128 } 1129 } 1130 1131 /* Wake up the poller. */ 1132 softint_schedule(sc->sc_si); 1133 1134 #if 0 /* XXX: broken */ 1135 #ifdef RND_COM 1136 rnd_add_uint32(&sc->rnd_source, intr ^ flagr); 1137 #endif 1138 #endif 1139 return (1); 1140 } 1141