1 /* $NetBSD: wmcom.c,v 1.8 2019/11/10 21:16:25 chs Exp $ */ 2 /* 3 * Copyright (c) 2012 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 #include <sys/cdefs.h> 28 __KERNEL_RCSID(0, "$NetBSD: wmcom.c,v 1.8 2019/11/10 21:16:25 chs Exp $"); 29 30 #include "rnd.h" 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/conf.h> 35 #include <sys/device.h> 36 #include <sys/errno.h> 37 #include <sys/fcntl.h> 38 #include <sys/intr.h> 39 #include <sys/kauth.h> 40 #include <sys/lwp.h> 41 #include <sys/malloc.h> 42 #include <sys/systm.h> 43 #include <sys/termios.h> 44 #include <sys/tty.h> 45 #include <sys/types.h> 46 47 #include <epoc32/windermere/windermerereg.h> 48 #include <epoc32/windermere/windermerevar.h> 49 50 #include <dev/cons.h> 51 52 #ifdef RND_COM 53 #include <sys/rndsource.h> 54 #endif 55 56 #include "ioconf.h" 57 #include "locators.h" 58 59 #define COMUNIT(x) TTUNIT(x) 60 #define COMDIALOUT(x) TTDIALOUT(x) 61 62 #define WMCOM_RING_SIZE 2048 63 64 struct wmcom_softc { 65 device_t sc_dev; 66 bus_space_tag_t sc_iot; 67 bus_space_handle_t sc_ioh; 68 69 void *sc_si; 70 71 struct tty *sc_tty; 72 73 u_char *sc_tba; 74 u_int sc_tbc; 75 u_char *sc_rbuf; 76 char *volatile sc_rbget; 77 char *volatile sc_rbput; 78 volatile int sc_rbavail; 79 80 int sc_tx_done; 81 int sc_rx_ready; 82 83 int sc_hwflags; 84 #define COM_HW_CONSOLE (1 << 0) 85 #define COM_HW_DEV_OK (1 << 1) 86 #define COM_HW_KGDB (1 << 2) 87 int sc_swflags; 88 89 int sc_flags; 90 #define WMCOM_IRDA (1 << 0) 91 92 #ifdef RND_COM 93 krandsource_t rnd_source; 94 #endif 95 }; 96 97 static int wmcom_match(device_t, cfdata_t, void *); 98 static void wmcom_attach(device_t, device_t, void *); 99 100 static int wmcom_intr(void *); 101 static void wmcom_soft(void *); 102 103 static void wmcom_start(struct tty *); 104 static int wmcom_param(struct tty *, struct termios *); 105 static int wmcom_hwiflow(struct tty *, int); 106 107 dev_type_open(wmcomopen); 108 dev_type_close(wmcomclose); 109 dev_type_read(wmcomread); 110 dev_type_write(wmcomwrite); 111 dev_type_ioctl(wmcomioctl); 112 dev_type_stop(wmcomstop); 113 dev_type_tty(wmcomtty); 114 dev_type_poll(wmcompoll); 115 116 static void wmcom_iflush(struct wmcom_softc *); 117 static void wmcom_shutdown(struct wmcom_softc *); 118 static void wmcom_break(struct wmcom_softc *, int); 119 120 static void wmcom_rxsoft(struct wmcom_softc *, struct tty *); 121 122 static inline uint32_t wmcom_rate2lcr(int); 123 static uint8_t wmcom_cflag2fcr(tcflag_t); 124 125 static int wmcom_cngetc(dev_t); 126 static void wmcom_cnputc(dev_t, int); 127 static void wmcom_cnpollc(dev_t, int); 128 129 CFATTACH_DECL_NEW(wmcom, sizeof(struct wmcom_softc), 130 wmcom_match, wmcom_attach, NULL, NULL); 131 132 const struct cdevsw wmcom_cdevsw = { 133 .d_open = wmcomopen, 134 .d_close = wmcomclose, 135 .d_read = wmcomread, 136 .d_write = wmcomwrite, 137 .d_ioctl = wmcomioctl, 138 .d_stop = wmcomstop, 139 .d_tty = wmcomtty, 140 .d_poll = wmcompoll, 141 .d_mmap = nommap, 142 .d_kqfilter = ttykqfilter, 143 .d_discard = nodiscard, 144 .d_flag = D_TTY 145 }; 146 147 static struct cnm_state wmcom_cnm_state; 148 static vaddr_t wmcom_cnaddr; 149 static int wmcom_cnrate; 150 static tcflag_t wmcom_cncflag; 151 152 153 /* ARGSUSED */ 154 static int 155 wmcom_match(device_t parent, cfdata_t match, void *aux) 156 { 157 struct windermere_attach_args *aa = aux; 158 159 /* Wildcard not accept */ 160 if (aa->aa_offset == WINDERMERECF_OFFSET_DEFAULT || 161 aa->aa_irq == WINDERMERECF_IRQ_DEFAULT) 162 return 0; 163 164 aa->aa_size = UART_SIZE; 165 return 1; 166 } 167 168 /* ARGSUSED */ 169 static void 170 wmcom_attach(device_t parent, device_t self, void *aux) 171 { 172 struct wmcom_softc *sc = device_private(self); 173 struct windermere_attach_args *aa = aux; 174 175 aprint_naive("\n"); 176 aprint_normal("\n"); 177 178 sc->sc_dev = self; 179 if (windermere_bus_space_subregion(aa->aa_iot, *aa->aa_ioh, 180 aa->aa_offset, aa->aa_size, &sc->sc_ioh) != 0) { 181 aprint_error_dev(self, "can't map registers\n"); 182 return; 183 } 184 sc->sc_iot = aa->aa_iot; 185 if (intr_establish(aa->aa_irq, IPL_SERIAL, 0, wmcom_intr, sc) == NULL) { 186 aprint_error_dev(self, "can't establish interrupt\n"); 187 return; 188 } 189 190 if (aa->aa_offset == (wmcom_cnaddr & 0xfff)) 191 SET(sc->sc_hwflags, COM_HW_CONSOLE); 192 193 if (aa->aa_offset == WINDERMERE_COM0_OFFSET) 194 SET(sc->sc_flags, WMCOM_IRDA); 195 196 sc->sc_tty = tty_alloc(); 197 sc->sc_tty->t_oproc = wmcom_start; 198 sc->sc_tty->t_param = wmcom_param; 199 sc->sc_tty->t_hwiflow = wmcom_hwiflow; 200 201 sc->sc_tbc = 0; 202 sc->sc_rbuf = malloc(WMCOM_RING_SIZE << 1, M_DEVBUF, M_WAITOK); 203 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 204 sc->sc_rbavail = WMCOM_RING_SIZE; 205 206 tty_attach(sc->sc_tty); 207 208 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 209 int maj = cdevsw_lookup_major(&wmcom_cdevsw); 210 211 sc->sc_tty->t_dev = makedev(maj, device_unit(sc->sc_dev)); 212 cn_tab->cn_dev = sc->sc_tty->t_dev; 213 214 aprint_normal_dev(self, "console\n"); 215 } 216 217 sc->sc_si = softint_establish(SOFTINT_SERIAL, wmcom_soft, sc); 218 219 #ifdef RND_COM 220 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 221 RND_TYPE_TTY, RND_FLAG_DEFAULT); 222 #endif 223 224 SET(sc->sc_hwflags, COM_HW_DEV_OK); 225 } 226 227 static int 228 wmcom_intr(void *arg) 229 { 230 struct wmcom_softc *sc = arg; 231 bus_space_tag_t iot = sc->sc_iot; 232 bus_space_handle_t ioh = sc->sc_ioh; 233 int cc; 234 uint32_t data; 235 uint8_t fr, intm; 236 u_char *put; 237 238 if (!device_is_active(sc->sc_dev)) 239 return 0; 240 241 fr = bus_space_read_1(iot, ioh, UARTFR); 242 intm = bus_space_read_1(iot, ioh, UARTINTM); 243 if (bus_space_read_1(iot, ioh, UARTINT) & INT_RXINT) { 244 put = sc->sc_rbput; 245 cc = sc->sc_rbavail; 246 while (cc > 0) { 247 if (ISSET(fr, FR_RXFE)) 248 break; 249 data = bus_space_read_4(iot, ioh, UARTDR); 250 cn_check_magic(sc->sc_tty->t_dev, data & 0xff, 251 wmcom_cnm_state); 252 253 put[0] = data & 0xff; 254 put[1] = (data >> 8) & 0xff; 255 put += 2; 256 if (put >= sc->sc_rbuf + (WMCOM_RING_SIZE << 1)) 257 put = sc->sc_rbuf; 258 cc--; 259 sc->sc_rx_ready = 1; 260 261 fr = bus_space_read_1(iot, ioh, UARTFR); 262 } 263 264 /* 265 * Current string of incoming characters ended because 266 * no more data was available or we ran out of space. 267 * Schedule a receive event if any data was received. 268 * If we're out of space, turn off receive interrupts. 269 */ 270 sc->sc_rbput = put; 271 sc->sc_rbavail = cc; 272 273 /* 274 * See if we are in danger of overflowing a buffer. If 275 * so, use hardware flow control to ease the pressure. 276 */ 277 278 /* but wmcom cannot. X-( */ 279 280 /* 281 * If we're out of space, disable receive interrupts 282 * until the queue has drained a bit. 283 */ 284 if (cc <= 0) 285 CLR(intm, INT_RXINT); 286 } 287 288 /* 289 * Done handling any receive interrupts. See if data can be 290 * transmitted as well. Schedule tx done event if no data left 291 * and tty was marked busy. 292 */ 293 294 if (!ISSET(fr, FR_TXFF)) { 295 /* Output the next chunk of the contiguous buffer, if any. */ 296 if (sc->sc_tbc > 0) { 297 while (sc->sc_tbc > 0 && !ISSET(fr, FR_TXFF)) { 298 bus_space_write_1(iot, ioh, UARTDR, 299 *sc->sc_tba); 300 sc->sc_tba++; 301 sc->sc_tbc--; 302 fr = bus_space_read_1(iot, ioh, UARTFR); 303 } 304 } else if (!ISSET(fr, FR_BUSY) && ISSET(intm, INT_TXINT)) { 305 CLR(intm, INT_TXINT); 306 sc->sc_tx_done = 1; 307 } 308 } 309 310 bus_space_write_1(iot, ioh, UARTINTM, intm); 311 312 /* Wake up the poller. */ 313 softint_schedule(sc->sc_si); 314 315 return 1; 316 } 317 318 static void 319 wmcom_soft(void *arg) 320 { 321 struct wmcom_softc *sc = arg; 322 struct tty *tp = sc->sc_tty; 323 324 if (!device_is_active(sc->sc_dev)) 325 return; 326 327 if (sc->sc_rx_ready) { 328 sc->sc_rx_ready = 0; 329 wmcom_rxsoft(sc, tp); 330 } 331 if (sc->sc_tx_done) { 332 sc->sc_tx_done = 0; 333 CLR(tp->t_state, TS_BUSY); 334 if (ISSET(tp->t_state, TS_FLUSH)) 335 CLR(tp->t_state, TS_FLUSH); 336 else 337 ndflush(&tp->t_outq, 338 (int)(sc->sc_tba - tp->t_outq.c_cf)); 339 (*tp->t_linesw->l_start)(tp); 340 } 341 } 342 343 static void 344 wmcom_start(struct tty *tp) 345 { 346 struct wmcom_softc *sc 347 = device_lookup_private(&wmcom_cd, COMUNIT(tp->t_dev)); 348 bus_space_tag_t iot = sc->sc_iot; 349 bus_space_handle_t ioh = sc->sc_ioh; 350 int s, n; 351 uint8_t intm; 352 353 if (!device_is_active(sc->sc_dev)) 354 return; 355 356 s = spltty(); 357 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 358 goto out; 359 if (!ttypull(tp)) 360 goto out; 361 362 /* Grab the first contiguous region of buffer space. */ 363 { 364 u_char *tba; 365 int tbc; 366 367 tba = tp->t_outq.c_cf; 368 tbc = ndqb(&tp->t_outq, 0); 369 370 (void)splserial(); 371 372 sc->sc_tba = tba; 373 sc->sc_tbc = tbc; 374 } 375 376 SET(tp->t_state, TS_BUSY); 377 378 intm = bus_space_read_1(iot, ioh, UARTINTM); 379 if (!ISSET(intm, INT_TXINT)) { 380 bus_space_write_1(iot, ioh, UARTINTM, intm | INT_TXINT); 381 382 /* Output the first chunk of the contiguous buffer. */ 383 n = uimin(sc->sc_tbc, UART_FIFO_SIZE); 384 bus_space_write_multi_1(iot, ioh, UARTDR, sc->sc_tba, n); 385 sc->sc_tba += n; 386 sc->sc_tbc -= n; 387 } 388 out: 389 splx(s); 390 return; 391 } 392 393 static int 394 wmcom_param(struct tty *tp, struct termios *t) 395 { 396 struct wmcom_softc *sc = 397 device_lookup_private(&wmcom_cd, COMUNIT(tp->t_dev)); 398 bus_space_tag_t iot = sc->sc_iot; 399 bus_space_handle_t ioh = sc->sc_ioh; 400 int s; 401 402 if (!device_is_active(sc->sc_dev)) 403 return ENXIO; 404 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 405 return EINVAL; 406 407 /* 408 * For the console, always force CLOCAL and !HUPCL, so that the port 409 * is always active. 410 */ 411 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 412 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 413 SET(t->c_cflag, CLOCAL); 414 CLR(t->c_cflag, HUPCL); 415 } 416 417 /* 418 * If there were no changes, don't do anything. This avoids dropping 419 * input and improves performance when all we did was frob things like 420 * VMIN and VTIME. 421 */ 422 if (tp->t_ospeed == t->c_ospeed && 423 tp->t_cflag == t->c_cflag) 424 return 0; 425 426 s = splserial(); 427 bus_space_write_4(iot, ioh, UARTLCR, wmcom_rate2lcr(t->c_ospeed)); 428 bus_space_write_1(iot, ioh, UARTFCR, wmcom_cflag2fcr(t->c_cflag)); 429 430 /* And copy to tty. */ 431 tp->t_ispeed = 0; 432 tp->t_ospeed = t->c_ospeed; 433 tp->t_cflag = t->c_cflag; 434 splx(s); 435 436 /* 437 * Update the tty layer's idea of the carrier bit. 438 * We tell tty the carrier is always on. 439 */ 440 (*tp->t_linesw->l_modem)(tp, 1); 441 442 return 0; 443 } 444 445 static int 446 wmcom_hwiflow(struct tty *tp, int block) 447 { 448 /* Nothing */ 449 return 0; 450 } 451 452 /* ARGSUSED */ 453 int 454 wmcomopen(dev_t dev, int flag, int mode, struct lwp *l) 455 { 456 struct wmcom_softc *sc; 457 struct tty *tp; 458 int error, s, s2; 459 uint8_t con; 460 461 sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 462 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK)) 463 return ENXIO; 464 if (!device_is_active(sc->sc_dev)) 465 return ENXIO; 466 467 #ifdef KGDB 468 /* 469 * If this is the kgdb port, no other use is permitted. 470 */ 471 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 472 return EBUSY; 473 #endif 474 475 tp = sc->sc_tty; 476 477 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 478 return EBUSY; 479 480 s = spltty(); 481 482 /* 483 * Do the following iff this is a first open. 484 */ 485 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 486 struct termios t; 487 488 tp->t_dev = dev; 489 490 /* Enable and turn on interrupt */ 491 con = CON_UARTEN; 492 if (ISSET(sc->sc_flags, WMCOM_IRDA)) 493 con |= CON_IRTXM; 494 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTCON, con); 495 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTINTM, INT_RXINT); 496 497 /* 498 * Initialize the termios status to the defaults. Add in the 499 * sticky bits from TIOCSFLAGS. 500 */ 501 t.c_ispeed = 0; 502 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 503 t.c_ospeed = wmcom_cnrate; 504 t.c_cflag = wmcom_cncflag; 505 } else { 506 t.c_ospeed = TTYDEF_SPEED; 507 t.c_cflag = TTYDEF_CFLAG; 508 } 509 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 510 SET(t.c_cflag, CLOCAL); 511 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 512 SET(t.c_cflag, CRTSCTS); 513 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 514 SET(t.c_cflag, MDMBUF); 515 /* Make sure wmcom_param() we do something */ 516 tp->t_ospeed = 0; 517 wmcom_param(tp, &t); 518 tp->t_iflag = TTYDEF_IFLAG; 519 tp->t_oflag = TTYDEF_OFLAG; 520 tp->t_lflag = TTYDEF_LFLAG; 521 ttychars(tp); 522 ttsetwater(tp); 523 524 s2 = splserial(); 525 526 /* Clear the input ring. */ 527 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 528 sc->sc_rbavail = WMCOM_RING_SIZE; 529 wmcom_iflush(sc); 530 531 splx(s2); 532 } 533 534 splx(s); 535 536 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 537 if (error) 538 goto bad; 539 540 error = (*tp->t_linesw->l_open)(dev, tp); 541 if (error) 542 goto bad; 543 return 0; 544 545 bad: 546 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 547 /* 548 * We failed to open the device, and nobody else had it opened. 549 * Clean up the state as appropriate. 550 */ 551 wmcom_shutdown(sc); 552 553 /* Disable UART */ 554 if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 555 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTCON, 0); 556 } 557 558 return error; 559 } 560 561 /* ARGSUSED */ 562 int 563 wmcomclose(dev_t dev, int flag, int mode, struct lwp *l) 564 { 565 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 566 struct tty *tp = sc->sc_tty; 567 568 /* XXXX This is for cons.c. */ 569 if (!ISSET(tp->t_state, TS_ISOPEN)) 570 return 0; 571 572 (*tp->t_linesw->l_close)(tp, flag); 573 ttyclose(tp); 574 575 if (!device_is_active(sc->sc_dev)) 576 return 0; 577 578 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 579 /* 580 * Although we got a last close, the device may still be in 581 * use; e.g. if this was the dialout node, and there are still 582 * processes waiting for carrier on the non-dialout node. 583 */ 584 wmcom_shutdown(sc); 585 586 /* Disable UART */ 587 if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 588 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTCON, 0); 589 } 590 591 return 0; 592 } 593 594 int 595 wmcomread(dev_t dev, struct uio *uio, int flag) 596 { 597 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 598 struct tty *tp = sc->sc_tty; 599 600 if (!device_is_active(sc->sc_dev)) 601 return EIO; 602 603 return (*tp->t_linesw->l_read)(tp, uio, flag); 604 } 605 606 int 607 wmcomwrite(dev_t dev, struct uio *uio, int flag) 608 { 609 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 610 struct tty *tp = sc->sc_tty; 611 612 if (!device_is_active(sc->sc_dev)) 613 return EIO; 614 615 return (*tp->t_linesw->l_write)(tp, uio, flag); 616 } 617 618 int 619 wmcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 620 { 621 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 622 struct tty *tp = sc->sc_tty; 623 int error, s; 624 625 if (!device_is_active(sc->sc_dev)) 626 return EIO; 627 628 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 629 if (error != EPASSTHROUGH) 630 return error; 631 632 error = ttioctl(tp, cmd, data, flag, l); 633 if (error != EPASSTHROUGH) 634 return error; 635 636 switch (cmd) { 637 case TIOCSFLAGS: 638 error = kauth_authorize_device_tty(l->l_cred, 639 KAUTH_DEVICE_TTY_PRIVSET, tp); 640 break; 641 default: 642 break; 643 } 644 if (error) 645 return error; 646 647 s = splserial(); 648 error = 0; 649 switch (cmd) { 650 case TIOCSBRK: 651 wmcom_break(sc, 1); 652 break; 653 654 case TIOCCBRK: 655 wmcom_break(sc, 0); 656 break; 657 658 case TIOCGFLAGS: 659 *(int *)data = sc->sc_swflags; 660 break; 661 662 case TIOCSFLAGS: 663 sc->sc_swflags = *(int *)data; 664 break; 665 666 default: 667 error = EPASSTHROUGH; 668 break; 669 } 670 splx(s); 671 return error; 672 } 673 674 int 675 wmcompoll(dev_t dev, int events, struct lwp *l) 676 { 677 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 678 struct tty *tp = sc->sc_tty; 679 680 if (!device_is_active(sc->sc_dev)) 681 return EIO; 682 683 return (*tp->t_linesw->l_poll)(tp, events, l); 684 } 685 686 struct tty * 687 wmcomtty(dev_t dev) 688 { 689 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 690 691 return sc->sc_tty; 692 } 693 694 void 695 wmcomstop(struct tty *tp, int flag) 696 { 697 int s; 698 699 s = splserial(); 700 if (ISSET(tp->t_state, TS_BUSY)) { 701 /* Stop transmitting at the next chunk. */ 702 if (!ISSET(tp->t_state, TS_TTSTOP)) 703 SET(tp->t_state, TS_FLUSH); 704 } 705 splx(s); 706 } 707 708 709 static void 710 wmcom_iflush(struct wmcom_softc *sc) 711 { 712 bus_space_tag_t iot = sc->sc_iot; 713 bus_space_handle_t ioh = sc->sc_ioh; 714 int timo; 715 716 timo = 50000; 717 while ((bus_space_read_1(iot, ioh, UARTFR) & FR_RXFE) == 0 && 718 timo--) 719 bus_space_read_1(iot, ioh, UARTDR); 720 if (timo == 0) 721 printf("%s: iflush timeout\n", device_xname(sc->sc_dev)); 722 } 723 724 static void 725 wmcom_shutdown(struct wmcom_softc *sc) 726 { 727 int s; 728 729 s = splserial(); 730 731 /* Turn off interrupt */ 732 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTINTM, 0); 733 734 /* Clear any break condition set with TIOCSBRK. */ 735 wmcom_break(sc, 0); 736 737 splx(s); 738 } 739 740 static void 741 wmcom_break(struct wmcom_softc *sc, int onoff) 742 { 743 int s; 744 uint8_t fcr; 745 746 s = splserial(); 747 fcr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, UARTFCR); 748 if (onoff) 749 SET(fcr, FCR_BREAK); 750 else 751 CLR(fcr, FCR_BREAK); 752 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTFCR, fcr); 753 splx(s); 754 } 755 756 static void 757 wmcom_rxsoft(struct wmcom_softc *sc, struct tty *tp) 758 { 759 bus_space_tag_t iot = sc->sc_iot; 760 bus_space_handle_t ioh = sc->sc_ioh; 761 int code, s; 762 u_int cc, scc; 763 uint8_t intm; 764 u_char sts, *get; 765 766 get = sc->sc_rbget; 767 scc = cc = WMCOM_RING_SIZE - sc->sc_rbavail; 768 while (cc) { 769 code = get[0]; 770 sts = get[1]; 771 if (ISSET(sts, RSR_FE | RSR_PE | RSR_OE)) { 772 if (ISSET(sts, (RSR_FE))) 773 SET(code, TTY_FE); 774 if (ISSET(sts, RSR_PE)) 775 SET(code, TTY_PE); 776 if (ISSET(sts, RSR_OE)) 777 ; /* XXXXX: Overrun */ 778 } 779 if ((*tp->t_linesw->l_rint)(code, tp) == -1) { 780 /* 781 * The line discipline's buffer is out of space. 782 */ 783 /* 784 * We're either not using flow control, or the 785 * line discipline didn't tell us to block for 786 * some reason. Either way, we have no way to 787 * know when there's more space available, so 788 * just drop the rest of the data. 789 */ 790 get += cc << 1; 791 if (get >= sc->sc_rbuf + (WMCOM_RING_SIZE << 1)) 792 get -= (WMCOM_RING_SIZE << 1); 793 cc = 0; 794 break; 795 } 796 get += 2; 797 if (get >= sc->sc_rbuf + (WMCOM_RING_SIZE << 1)) 798 get = sc->sc_rbuf; 799 cc--; 800 } 801 802 if (cc != scc) { 803 sc->sc_rbget = get; 804 s = splserial(); 805 806 cc = sc->sc_rbavail += scc - cc; 807 /* Buffers should be ok again, release possible block. */ 808 if (cc >= 1) { 809 intm = bus_space_read_1(iot, ioh, UARTINTM); 810 SET(intm, INT_RXINT); 811 bus_space_write_1(iot, ioh, UARTINTM, intm); 812 } 813 splx(s); 814 } 815 } 816 817 static inline uint32_t 818 wmcom_rate2lcr(int rate) 819 { 820 821 return 7372800 / (16 * rate) - 1; 822 } 823 824 static uint8_t 825 wmcom_cflag2fcr(tcflag_t cflag) 826 { 827 int8_t fcr = FCR_UFIFOEN; 828 829 switch (cflag & CSIZE) { 830 case CS5: SET(fcr, FCR_WLEN_5); break; 831 case CS6: SET(fcr, FCR_WLEN_6); break; 832 case CS7: SET(fcr, FCR_WLEN_7); break; 833 case CS8: SET(fcr, FCR_WLEN_8); break; 834 default: SET(fcr, FCR_WLEN_8); break; 835 } 836 if (cflag & CSTOPB) 837 SET(fcr, FCR_XSTOP); 838 if (cflag & PARENB) { 839 SET(fcr, (FCR_PRTEN | FCR_EVENPRT)); 840 if (cflag & PARODD) 841 CLR(fcr, FCR_EVENPRT); 842 } 843 return fcr; 844 } 845 846 #define WMCOM_CNREAD_1(offset) \ 847 (*(volatile uint8_t *)(wmcom_cnaddr + ((offset) << 2))) 848 #define WMCOM_CNREAD_4(offset) \ 849 (*(volatile uint32_t *)(wmcom_cnaddr + ((offset) << 2))) 850 #define WMCOM_CNWRITE_1(offset, val) \ 851 (*(volatile uint8_t *)(wmcom_cnaddr + ((offset) << 2)) = val) 852 #define WMCOM_CNWRITE_4(offset, val) \ 853 (*(volatile uint32_t *)(wmcom_cnaddr + ((offset) << 2)) = val) 854 855 static struct consdev wmcomcons = { 856 NULL, NULL, wmcom_cngetc, wmcom_cnputc, wmcom_cnpollc, NULL, NULL, NULL, 857 NODEV, CN_NORMAL 858 }; 859 860 int 861 wmcom_cnattach(vaddr_t addr, int rate, tcflag_t cflag, int irda) 862 { 863 864 wmcom_cnaddr = addr; 865 wmcom_cnrate = rate; 866 wmcom_cncflag = cflag; 867 WMCOM_CNWRITE_4(UARTLCR, wmcom_rate2lcr(rate)); 868 WMCOM_CNWRITE_1(UARTFCR, wmcom_cflag2fcr(cflag)); 869 if (irda) 870 WMCOM_CNWRITE_1(UARTCON, CON_UARTEN | CON_IRTXM); 871 else 872 WMCOM_CNWRITE_1(UARTCON, CON_UARTEN); 873 874 cn_tab = &wmcomcons; 875 cn_init_magic(&wmcom_cnm_state); 876 cn_set_magic("\047\001"); /* default magic is BREAK */ 877 878 return 0; 879 } 880 881 /* ARGSUSED */ 882 static int 883 wmcom_cngetc(dev_t dev) 884 { 885 int s = splserial(); 886 char ch; 887 888 while (WMCOM_CNREAD_1(UARTFR) & FR_RXFE); 889 890 ch = WMCOM_CNREAD_4(UARTDR); 891 892 { 893 #ifdef DDB 894 extern int db_active; 895 if (!db_active) 896 #endif 897 cn_check_magic(dev, ch, wmcom_cnm_state); 898 } 899 900 splx(s); 901 return ch; 902 } 903 904 /* ARGSUSED */ 905 static void 906 wmcom_cnputc(dev_t dev, int c) 907 { 908 int s = splserial(); 909 910 while (WMCOM_CNREAD_1(UARTFR) & FR_TXFF); 911 912 WMCOM_CNWRITE_1(UARTDR, c); 913 914 /* Make sure output. */ 915 while (WMCOM_CNREAD_1(UARTFR) & FR_BUSY); 916 917 splx(s); 918 } 919 920 /* ARGSUSED */ 921 static void 922 wmcom_cnpollc(dev_t dev, int on) 923 { 924 /* Nothing */ 925 } 926