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