1 /* $NetBSD: wmcom.c,v 1.6 2015/04/13 21:18:41 riastradh 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.6 2015/04/13 21:18:41 riastradh 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_NOWAIT); 203 if (sc->sc_rbuf == NULL) { 204 aprint_error_dev(self, "unable to allocate ring buffer\n"); 205 return; 206 } 207 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 208 sc->sc_rbavail = WMCOM_RING_SIZE; 209 210 tty_attach(sc->sc_tty); 211 212 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 213 int maj = cdevsw_lookup_major(&wmcom_cdevsw); 214 215 sc->sc_tty->t_dev = makedev(maj, device_unit(sc->sc_dev)); 216 cn_tab->cn_dev = sc->sc_tty->t_dev; 217 218 aprint_normal_dev(self, "console\n"); 219 } 220 221 sc->sc_si = softint_establish(SOFTINT_SERIAL, wmcom_soft, sc); 222 223 #ifdef RND_COM 224 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 225 RND_TYPE_TTY, RND_FLAG_DEFAULT); 226 #endif 227 228 SET(sc->sc_hwflags, COM_HW_DEV_OK); 229 } 230 231 static int 232 wmcom_intr(void *arg) 233 { 234 struct wmcom_softc *sc = arg; 235 bus_space_tag_t iot = sc->sc_iot; 236 bus_space_handle_t ioh = sc->sc_ioh; 237 int cc; 238 uint32_t data; 239 uint8_t fr, intm; 240 u_char *put; 241 242 if (!device_is_active(sc->sc_dev)) 243 return 0; 244 245 fr = bus_space_read_1(iot, ioh, UARTFR); 246 intm = bus_space_read_1(iot, ioh, UARTINTM); 247 if (bus_space_read_1(iot, ioh, UARTINT) & INT_RXINT) { 248 put = sc->sc_rbput; 249 cc = sc->sc_rbavail; 250 while (cc > 0) { 251 if (ISSET(fr, FR_RXFE)) 252 break; 253 data = bus_space_read_4(iot, ioh, UARTDR); 254 cn_check_magic(sc->sc_tty->t_dev, data & 0xff, 255 wmcom_cnm_state); 256 257 put[0] = data & 0xff; 258 put[1] = (data >> 8) & 0xff; 259 put += 2; 260 if (put >= sc->sc_rbuf + (WMCOM_RING_SIZE << 1)) 261 put = sc->sc_rbuf; 262 cc--; 263 sc->sc_rx_ready = 1; 264 265 fr = bus_space_read_1(iot, ioh, UARTFR); 266 } 267 268 /* 269 * Current string of incoming characters ended because 270 * no more data was available or we ran out of space. 271 * Schedule a receive event if any data was received. 272 * If we're out of space, turn off receive interrupts. 273 */ 274 sc->sc_rbput = put; 275 sc->sc_rbavail = cc; 276 277 /* 278 * See if we are in danger of overflowing a buffer. If 279 * so, use hardware flow control to ease the pressure. 280 */ 281 282 /* but wmcom cannot. X-( */ 283 284 /* 285 * If we're out of space, disable receive interrupts 286 * until the queue has drained a bit. 287 */ 288 if (cc <= 0) 289 CLR(intm, INT_RXINT); 290 } 291 292 /* 293 * Done handling any receive interrupts. See if data can be 294 * transmitted as well. Schedule tx done event if no data left 295 * and tty was marked busy. 296 */ 297 298 if (!ISSET(fr, FR_TXFF)) { 299 /* Output the next chunk of the contiguous buffer, if any. */ 300 if (sc->sc_tbc > 0) { 301 while (sc->sc_tbc > 0 && !ISSET(fr, FR_TXFF)) { 302 bus_space_write_1(iot, ioh, UARTDR, 303 *sc->sc_tba); 304 sc->sc_tba++; 305 sc->sc_tbc--; 306 fr = bus_space_read_1(iot, ioh, UARTFR); 307 } 308 } else if (!ISSET(fr, FR_BUSY) && ISSET(intm, INT_TXINT)) { 309 CLR(intm, INT_TXINT); 310 sc->sc_tx_done = 1; 311 } 312 } 313 314 bus_space_write_1(iot, ioh, UARTINTM, intm); 315 316 /* Wake up the poller. */ 317 softint_schedule(sc->sc_si); 318 319 return 1; 320 } 321 322 static void 323 wmcom_soft(void *arg) 324 { 325 struct wmcom_softc *sc = arg; 326 struct tty *tp = sc->sc_tty; 327 328 if (!device_is_active(sc->sc_dev)) 329 return; 330 331 if (sc->sc_rx_ready) { 332 sc->sc_rx_ready = 0; 333 wmcom_rxsoft(sc, tp); 334 } 335 if (sc->sc_tx_done) { 336 sc->sc_tx_done = 0; 337 CLR(tp->t_state, TS_BUSY); 338 if (ISSET(tp->t_state, TS_FLUSH)) 339 CLR(tp->t_state, TS_FLUSH); 340 else 341 ndflush(&tp->t_outq, 342 (int)(sc->sc_tba - tp->t_outq.c_cf)); 343 (*tp->t_linesw->l_start)(tp); 344 } 345 } 346 347 static void 348 wmcom_start(struct tty *tp) 349 { 350 struct wmcom_softc *sc 351 = device_lookup_private(&wmcom_cd, COMUNIT(tp->t_dev)); 352 bus_space_tag_t iot = sc->sc_iot; 353 bus_space_handle_t ioh = sc->sc_ioh; 354 int s, n; 355 uint8_t intm; 356 357 if (!device_is_active(sc->sc_dev)) 358 return; 359 360 s = spltty(); 361 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 362 goto out; 363 if (!ttypull(tp)) 364 goto out; 365 366 /* Grab the first contiguous region of buffer space. */ 367 { 368 u_char *tba; 369 int tbc; 370 371 tba = tp->t_outq.c_cf; 372 tbc = ndqb(&tp->t_outq, 0); 373 374 (void)splserial(); 375 376 sc->sc_tba = tba; 377 sc->sc_tbc = tbc; 378 } 379 380 SET(tp->t_state, TS_BUSY); 381 382 intm = bus_space_read_1(iot, ioh, UARTINTM); 383 if (!ISSET(intm, INT_TXINT)) { 384 bus_space_write_1(iot, ioh, UARTINTM, intm | INT_TXINT); 385 386 /* Output the first chunk of the contiguous buffer. */ 387 n = min(sc->sc_tbc, UART_FIFO_SIZE); 388 bus_space_write_multi_1(iot, ioh, UARTDR, sc->sc_tba, n); 389 sc->sc_tba += n; 390 sc->sc_tbc -= n; 391 } 392 out: 393 splx(s); 394 return; 395 } 396 397 static int 398 wmcom_param(struct tty *tp, struct termios *t) 399 { 400 struct wmcom_softc *sc = 401 device_lookup_private(&wmcom_cd, COMUNIT(tp->t_dev)); 402 bus_space_tag_t iot = sc->sc_iot; 403 bus_space_handle_t ioh = sc->sc_ioh; 404 int s; 405 406 if (!device_is_active(sc->sc_dev)) 407 return ENXIO; 408 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 409 return EINVAL; 410 411 /* 412 * For the console, always force CLOCAL and !HUPCL, so that the port 413 * is always active. 414 */ 415 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 416 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 417 SET(t->c_cflag, CLOCAL); 418 CLR(t->c_cflag, HUPCL); 419 } 420 421 /* 422 * If there were no changes, don't do anything. This avoids dropping 423 * input and improves performance when all we did was frob things like 424 * VMIN and VTIME. 425 */ 426 if (tp->t_ospeed == t->c_ospeed && 427 tp->t_cflag == t->c_cflag) 428 return 0; 429 430 s = splserial(); 431 bus_space_write_4(iot, ioh, UARTLCR, wmcom_rate2lcr(t->c_ospeed)); 432 bus_space_write_1(iot, ioh, UARTFCR, wmcom_cflag2fcr(t->c_cflag)); 433 434 /* And copy to tty. */ 435 tp->t_ispeed = 0; 436 tp->t_ospeed = t->c_ospeed; 437 tp->t_cflag = t->c_cflag; 438 splx(s); 439 440 /* 441 * Update the tty layer's idea of the carrier bit. 442 * We tell tty the carrier is always on. 443 */ 444 (*tp->t_linesw->l_modem)(tp, 1); 445 446 return 0; 447 } 448 449 static int 450 wmcom_hwiflow(struct tty *tp, int block) 451 { 452 /* Nothing */ 453 return 0; 454 } 455 456 /* ARGSUSED */ 457 int 458 wmcomopen(dev_t dev, int flag, int mode, struct lwp *l) 459 { 460 struct wmcom_softc *sc; 461 struct tty *tp; 462 int error, s, s2; 463 uint8_t con; 464 465 sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 466 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK)) 467 return ENXIO; 468 if (!device_is_active(sc->sc_dev)) 469 return ENXIO; 470 471 #ifdef KGDB 472 /* 473 * If this is the kgdb port, no other use is permitted. 474 */ 475 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 476 return EBUSY; 477 #endif 478 479 tp = sc->sc_tty; 480 481 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 482 return EBUSY; 483 484 s = spltty(); 485 486 /* 487 * Do the following iff this is a first open. 488 */ 489 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 490 struct termios t; 491 492 tp->t_dev = dev; 493 494 /* Enable and turn on interrupt */ 495 con = CON_UARTEN; 496 if (ISSET(sc->sc_flags, WMCOM_IRDA)) 497 con |= CON_IRTXM; 498 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTCON, con); 499 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTINTM, INT_RXINT); 500 501 /* 502 * Initialize the termios status to the defaults. Add in the 503 * sticky bits from TIOCSFLAGS. 504 */ 505 t.c_ispeed = 0; 506 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 507 t.c_ospeed = wmcom_cnrate; 508 t.c_cflag = wmcom_cncflag; 509 } else { 510 t.c_ospeed = TTYDEF_SPEED; 511 t.c_cflag = TTYDEF_CFLAG; 512 } 513 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 514 SET(t.c_cflag, CLOCAL); 515 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 516 SET(t.c_cflag, CRTSCTS); 517 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 518 SET(t.c_cflag, MDMBUF); 519 /* Make sure wmcom_param() we do something */ 520 tp->t_ospeed = 0; 521 wmcom_param(tp, &t); 522 tp->t_iflag = TTYDEF_IFLAG; 523 tp->t_oflag = TTYDEF_OFLAG; 524 tp->t_lflag = TTYDEF_LFLAG; 525 ttychars(tp); 526 ttsetwater(tp); 527 528 s2 = splserial(); 529 530 /* Clear the input ring. */ 531 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 532 sc->sc_rbavail = WMCOM_RING_SIZE; 533 wmcom_iflush(sc); 534 535 splx(s2); 536 } 537 538 splx(s); 539 540 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 541 if (error) 542 goto bad; 543 544 error = (*tp->t_linesw->l_open)(dev, tp); 545 if (error) 546 goto bad; 547 return 0; 548 549 bad: 550 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 551 /* 552 * We failed to open the device, and nobody else had it opened. 553 * Clean up the state as appropriate. 554 */ 555 wmcom_shutdown(sc); 556 557 /* Disable UART */ 558 if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 559 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTCON, 0); 560 } 561 562 return error; 563 } 564 565 /* ARGSUSED */ 566 int 567 wmcomclose(dev_t dev, int flag, int mode, struct lwp *l) 568 { 569 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 570 struct tty *tp = sc->sc_tty; 571 572 /* XXXX This is for cons.c. */ 573 if (!ISSET(tp->t_state, TS_ISOPEN)) 574 return 0; 575 576 (*tp->t_linesw->l_close)(tp, flag); 577 ttyclose(tp); 578 579 if (!device_is_active(sc->sc_dev)) 580 return 0; 581 582 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 583 /* 584 * Although we got a last close, the device may still be in 585 * use; e.g. if this was the dialout node, and there are still 586 * processes waiting for carrier on the non-dialout node. 587 */ 588 wmcom_shutdown(sc); 589 590 /* Disable UART */ 591 if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 592 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTCON, 0); 593 } 594 595 return 0; 596 } 597 598 int 599 wmcomread(dev_t dev, struct uio *uio, int flag) 600 { 601 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 602 struct tty *tp = sc->sc_tty; 603 604 if (!device_is_active(sc->sc_dev)) 605 return EIO; 606 607 return (*tp->t_linesw->l_read)(tp, uio, flag); 608 } 609 610 int 611 wmcomwrite(dev_t dev, struct uio *uio, int flag) 612 { 613 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 614 struct tty *tp = sc->sc_tty; 615 616 if (!device_is_active(sc->sc_dev)) 617 return EIO; 618 619 return (*tp->t_linesw->l_write)(tp, uio, flag); 620 } 621 622 int 623 wmcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 624 { 625 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 626 struct tty *tp = sc->sc_tty; 627 int error, s; 628 629 if (!device_is_active(sc->sc_dev)) 630 return EIO; 631 632 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 633 if (error != EPASSTHROUGH) 634 return error; 635 636 error = ttioctl(tp, cmd, data, flag, l); 637 if (error != EPASSTHROUGH) 638 return error; 639 640 switch (cmd) { 641 case TIOCSFLAGS: 642 error = kauth_authorize_device_tty(l->l_cred, 643 KAUTH_DEVICE_TTY_PRIVSET, tp); 644 break; 645 default: 646 break; 647 } 648 if (error) 649 return error; 650 651 s = splserial(); 652 error = 0; 653 switch (cmd) { 654 case TIOCSBRK: 655 wmcom_break(sc, 1); 656 break; 657 658 case TIOCCBRK: 659 wmcom_break(sc, 0); 660 break; 661 662 case TIOCGFLAGS: 663 *(int *)data = sc->sc_swflags; 664 break; 665 666 case TIOCSFLAGS: 667 sc->sc_swflags = *(int *)data; 668 break; 669 670 default: 671 error = EPASSTHROUGH; 672 break; 673 } 674 splx(s); 675 return error; 676 } 677 678 int 679 wmcompoll(dev_t dev, int events, struct lwp *l) 680 { 681 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 682 struct tty *tp = sc->sc_tty; 683 684 if (!device_is_active(sc->sc_dev)) 685 return EIO; 686 687 return (*tp->t_linesw->l_poll)(tp, events, l); 688 } 689 690 struct tty * 691 wmcomtty(dev_t dev) 692 { 693 struct wmcom_softc *sc = device_lookup_private(&wmcom_cd, COMUNIT(dev)); 694 695 return sc->sc_tty; 696 } 697 698 void 699 wmcomstop(struct tty *tp, int flag) 700 { 701 int s; 702 703 s = splserial(); 704 if (ISSET(tp->t_state, TS_BUSY)) { 705 /* Stop transmitting at the next chunk. */ 706 if (!ISSET(tp->t_state, TS_TTSTOP)) 707 SET(tp->t_state, TS_FLUSH); 708 } 709 splx(s); 710 } 711 712 713 static void 714 wmcom_iflush(struct wmcom_softc *sc) 715 { 716 bus_space_tag_t iot = sc->sc_iot; 717 bus_space_handle_t ioh = sc->sc_ioh; 718 int timo; 719 720 timo = 50000; 721 while ((bus_space_read_1(iot, ioh, UARTFR) & FR_RXFE) == 0 && 722 timo--) 723 bus_space_read_1(iot, ioh, UARTDR); 724 if (timo == 0) 725 printf("%s: iflush timeout\n", device_xname(sc->sc_dev)); 726 } 727 728 static void 729 wmcom_shutdown(struct wmcom_softc *sc) 730 { 731 int s; 732 733 s = splserial(); 734 735 /* Turn off interrupt */ 736 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTINTM, 0); 737 738 /* Clear any break condition set with TIOCSBRK. */ 739 wmcom_break(sc, 0); 740 741 splx(s); 742 } 743 744 static void 745 wmcom_break(struct wmcom_softc *sc, int onoff) 746 { 747 int s; 748 uint8_t fcr; 749 750 s = splserial(); 751 fcr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, UARTFCR); 752 if (onoff) 753 SET(fcr, FCR_BREAK); 754 else 755 CLR(fcr, FCR_BREAK); 756 bus_space_write_1(sc->sc_iot, sc->sc_ioh, UARTFCR, fcr); 757 splx(s); 758 } 759 760 static void 761 wmcom_rxsoft(struct wmcom_softc *sc, struct tty *tp) 762 { 763 bus_space_tag_t iot = sc->sc_iot; 764 bus_space_handle_t ioh = sc->sc_ioh; 765 int code, s; 766 u_int cc, scc; 767 uint8_t intm; 768 u_char sts, *get; 769 770 get = sc->sc_rbget; 771 scc = cc = WMCOM_RING_SIZE - sc->sc_rbavail; 772 while (cc) { 773 code = get[0]; 774 sts = get[1]; 775 if (ISSET(sts, RSR_FE | RSR_PE | RSR_OE)) { 776 if (ISSET(sts, (RSR_FE))) 777 SET(code, TTY_FE); 778 if (ISSET(sts, RSR_PE)) 779 SET(code, TTY_PE); 780 if (ISSET(sts, RSR_OE)) 781 ; /* XXXXX: Overrun */ 782 } 783 if ((*tp->t_linesw->l_rint)(code, tp) == -1) { 784 /* 785 * The line discipline's buffer is out of space. 786 */ 787 /* 788 * We're either not using flow control, or the 789 * line discipline didn't tell us to block for 790 * some reason. Either way, we have no way to 791 * know when there's more space available, so 792 * just drop the rest of the data. 793 */ 794 get += cc << 1; 795 if (get >= sc->sc_rbuf + (WMCOM_RING_SIZE << 1)) 796 get -= (WMCOM_RING_SIZE << 1); 797 cc = 0; 798 break; 799 } 800 get += 2; 801 if (get >= sc->sc_rbuf + (WMCOM_RING_SIZE << 1)) 802 get = sc->sc_rbuf; 803 cc--; 804 } 805 806 if (cc != scc) { 807 sc->sc_rbget = get; 808 s = splserial(); 809 810 cc = sc->sc_rbavail += scc - cc; 811 /* Buffers should be ok again, release possible block. */ 812 if (cc >= 1) { 813 intm = bus_space_read_1(iot, ioh, UARTINTM); 814 SET(intm, INT_RXINT); 815 bus_space_write_1(iot, ioh, UARTINTM, intm); 816 } 817 splx(s); 818 } 819 } 820 821 static inline uint32_t 822 wmcom_rate2lcr(int rate) 823 { 824 825 return 7372800 / (16 * rate) - 1; 826 } 827 828 static uint8_t 829 wmcom_cflag2fcr(tcflag_t cflag) 830 { 831 int8_t fcr = FCR_UFIFOEN; 832 833 switch (cflag & CSIZE) { 834 case CS5: SET(fcr, FCR_WLEN_5); break; 835 case CS6: SET(fcr, FCR_WLEN_6); break; 836 case CS7: SET(fcr, FCR_WLEN_7); break; 837 case CS8: SET(fcr, FCR_WLEN_8); break; 838 default: SET(fcr, FCR_WLEN_8); break; 839 } 840 if (cflag & CSTOPB) 841 SET(fcr, FCR_XSTOP); 842 if (cflag & PARENB) { 843 SET(fcr, (FCR_PRTEN | FCR_EVENPRT)); 844 if (cflag & PARODD) 845 CLR(fcr, FCR_EVENPRT); 846 } 847 return fcr; 848 } 849 850 #define WMCOM_CNREAD_1(offset) \ 851 (*(volatile uint8_t *)(wmcom_cnaddr + ((offset) << 2))) 852 #define WMCOM_CNREAD_4(offset) \ 853 (*(volatile uint32_t *)(wmcom_cnaddr + ((offset) << 2))) 854 #define WMCOM_CNWRITE_1(offset, val) \ 855 (*(volatile uint8_t *)(wmcom_cnaddr + ((offset) << 2)) = val) 856 #define WMCOM_CNWRITE_4(offset, val) \ 857 (*(volatile uint32_t *)(wmcom_cnaddr + ((offset) << 2)) = val) 858 859 static struct consdev wmcomcons = { 860 NULL, NULL, wmcom_cngetc, wmcom_cnputc, wmcom_cnpollc, NULL, NULL, NULL, 861 NODEV, CN_NORMAL 862 }; 863 864 int 865 wmcom_cnattach(vaddr_t addr, int rate, tcflag_t cflag, int irda) 866 { 867 868 wmcom_cnaddr = addr; 869 wmcom_cnrate = rate; 870 wmcom_cncflag = cflag; 871 WMCOM_CNWRITE_4(UARTLCR, wmcom_rate2lcr(rate)); 872 WMCOM_CNWRITE_1(UARTFCR, wmcom_cflag2fcr(cflag)); 873 if (irda) 874 WMCOM_CNWRITE_1(UARTCON, CON_UARTEN | CON_IRTXM); 875 else 876 WMCOM_CNWRITE_1(UARTCON, CON_UARTEN); 877 878 cn_tab = &wmcomcons; 879 cn_init_magic(&wmcom_cnm_state); 880 cn_set_magic("\047\001"); /* default magic is BREAK */ 881 882 return 0; 883 } 884 885 /* ARGSUSED */ 886 static int 887 wmcom_cngetc(dev_t dev) 888 { 889 int s = splserial(); 890 char ch; 891 892 while (WMCOM_CNREAD_1(UARTFR) & FR_RXFE); 893 894 ch = WMCOM_CNREAD_4(UARTDR); 895 896 { 897 #ifdef DDB 898 extern int db_active; 899 if (!db_active) 900 #endif 901 cn_check_magic(dev, ch, wmcom_cnm_state); 902 } 903 904 splx(s); 905 return ch; 906 } 907 908 /* ARGSUSED */ 909 static void 910 wmcom_cnputc(dev_t dev, int c) 911 { 912 int s = splserial(); 913 914 while (WMCOM_CNREAD_1(UARTFR) & FR_TXFF); 915 916 WMCOM_CNWRITE_1(UARTDR, c); 917 918 /* Make sure output. */ 919 while (WMCOM_CNREAD_1(UARTFR) & FR_BUSY); 920 921 splx(s); 922 } 923 924 /* ARGSUSED */ 925 static void 926 wmcom_cnpollc(dev_t dev, int on) 927 { 928 /* Nothing */ 929 } 930