1 /* $NetBSD: clpscom.c,v 1.6 2015/04/13 21:18:41 riastradh Exp $ */ 2 /* 3 * Copyright (c) 2013 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: clpscom.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 <arm/clps711x/clps711xreg.h> 48 #include <arm/clps711x/clpssocvar.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 CLPSCOM_RING_SIZE 2048 63 #define UART_FIFO_SIZE 16 64 65 #define CLPSCOM_READ_CON(sc) \ 66 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON) 67 #define CLPSCOM_WRITE_CON(sc, val) \ 68 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON, (val)) 69 #define CLPSCOM_READ_FLG(sc) \ 70 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG) 71 #define CLPSCOM_WRITE_FLG(sc, val) \ 72 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG, (val)) 73 #define CLPSCOM_READ(sc) \ 74 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR) 75 #define CLPSCOM_WRITE(sc, val) \ 76 bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val)) 77 #define CLPSCOM_WRITE_MULTI(sc, val, n) \ 78 bus_space_write_multi_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val), (n)) 79 #define CLPSCOM_READ_UBRLCR(sc) \ 80 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR) 81 #define CLPSCOM_WRITE_UBRLCR(sc, val) \ 82 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR, (val)) 83 84 struct clpscom_softc { 85 device_t sc_dev; 86 bus_space_tag_t sc_iot; 87 bus_space_handle_t sc_ioh; 88 int sc_irq[3]; 89 void *sc_ih[3]; 90 #define CLPSCOM_TXINT 0 91 #define CLPSCOM_RXINT 1 92 #define CLPSCOM_MSINT 2 93 94 void *sc_si; 95 96 struct tty *sc_tty; 97 98 u_char *sc_tba; 99 u_int sc_tbc; 100 u_char *sc_rbuf; 101 char *volatile sc_rbget; 102 char *volatile sc_rbput; 103 volatile int sc_rbavail; 104 105 #define CLPSCOM_MODEM_STATUS_MASK (SYSFLG_DCD | SYSFLG_DSR | SYSFLG_CTS) 106 uint32_t sc_ms; 107 uint32_t sc_ms_dcd; 108 uint32_t sc_ms_cts; 109 uint32_t sc_ms_mask; 110 uint32_t sc_ms_delta; 111 112 int sc_tx_stopped; 113 114 int sc_tx_done; 115 int sc_rx_ready; 116 int sc_ms_changed; 117 118 int sc_hwflags; 119 #define COM_HW_CONSOLE (1 << 0) 120 #define COM_HW_DEV_OK (1 << 1) 121 #define COM_HW_KGDB (1 << 2) 122 int sc_swflags; 123 124 #ifdef RND_COM 125 krandsource_t rnd_source; 126 #endif 127 }; 128 129 static int clpscom_match(device_t, cfdata_t, void *); 130 static void clpscom_attach(device_t, device_t, void *); 131 132 static int clpscom_txintr(void *); 133 static int clpscom_rxintr(void *); 134 static int clpscom_msintr(void *); 135 static void clpscom_soft(void *); 136 137 static void clpscom_start(struct tty *); 138 static int clpscom_param(struct tty *, struct termios *); 139 static int clpscom_hwiflow(struct tty *, int); 140 141 dev_type_open(clpscomopen); 142 dev_type_close(clpscomclose); 143 dev_type_read(clpscomread); 144 dev_type_write(clpscomwrite); 145 dev_type_ioctl(clpscomioctl); 146 dev_type_stop(clpscomstop); 147 dev_type_tty(clpscomtty); 148 dev_type_poll(clpscompoll); 149 150 static void clpscom_iflush(struct clpscom_softc *); 151 static void clpscom_shutdown(struct clpscom_softc *); 152 static void clpscom_break(struct clpscom_softc *, int); 153 static int clpscom_to_tiocm(struct clpscom_softc *); 154 155 static void clpscom_rxsoft(struct clpscom_softc *, struct tty *); 156 static void clpscom_mssoft(struct clpscom_softc *, struct tty *); 157 158 static inline uint32_t clpscom_rate2ubrlcr(int); 159 static uint32_t clpscom_cflag2ubrlcr(tcflag_t); 160 161 static int clpscom_cngetc(dev_t); 162 static void clpscom_cnputc(dev_t, int); 163 static void clpscom_cnpollc(dev_t, int); 164 165 CFATTACH_DECL_NEW(clpscom, sizeof(struct clpscom_softc), 166 clpscom_match, clpscom_attach, NULL, NULL); 167 168 const struct cdevsw clpscom_cdevsw = { 169 .d_open = clpscomopen, 170 .d_close = clpscomclose, 171 .d_read = clpscomread, 172 .d_write = clpscomwrite, 173 .d_ioctl = clpscomioctl, 174 .d_stop = clpscomstop, 175 .d_tty = clpscomtty, 176 .d_poll = clpscompoll, 177 .d_mmap = nommap, 178 .d_kqfilter = ttykqfilter, 179 .d_discard = nodiscard, 180 .d_flag = D_TTY 181 }; 182 183 static struct cnm_state clpscom_cnm_state; 184 static vaddr_t clpscom_cnaddr = 0; 185 static int clpscom_cnrate; 186 static tcflag_t clpscom_cncflag; 187 188 189 /* ARGSUSED */ 190 static int 191 clpscom_match(device_t parent, cfdata_t match, void *aux) 192 { 193 194 return 1; 195 } 196 197 /* ARGSUSED */ 198 static void 199 clpscom_attach(device_t parent, device_t self, void *aux) 200 { 201 struct clpscom_softc *sc = device_private(self); 202 struct clpssoc_attach_args *aa = aux; 203 int i; 204 205 aprint_naive("\n"); 206 aprint_normal("\n"); 207 208 sc->sc_dev = self; 209 sc->sc_iot = aa->aa_iot; 210 sc->sc_ioh = *aa->aa_ioh; 211 for (i = 0; i < __arraycount(aa->aa_irq); i++) { 212 sc->sc_irq[i] = aa->aa_irq[i]; 213 sc->sc_ih[i] = NULL; 214 } 215 216 if (clpscom_cnaddr != 0) 217 SET(sc->sc_hwflags, COM_HW_CONSOLE); 218 219 sc->sc_tty = tty_alloc(); 220 sc->sc_tty->t_oproc = clpscom_start; 221 sc->sc_tty->t_param = clpscom_param; 222 sc->sc_tty->t_hwiflow = clpscom_hwiflow; 223 224 sc->sc_tbc = 0; 225 sc->sc_rbuf = malloc(CLPSCOM_RING_SIZE << 1, M_DEVBUF, M_NOWAIT); 226 if (sc->sc_rbuf == NULL) { 227 aprint_error_dev(self, "unable to allocate ring buffer\n"); 228 return; 229 } 230 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 231 sc->sc_rbavail = CLPSCOM_RING_SIZE; 232 233 tty_attach(sc->sc_tty); 234 235 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 236 int maj = cdevsw_lookup_major(&clpscom_cdevsw); 237 238 sc->sc_tty->t_dev = makedev(maj, device_unit(sc->sc_dev)); 239 cn_tab->cn_dev = sc->sc_tty->t_dev; 240 241 aprint_normal_dev(self, "console\n"); 242 } 243 244 sc->sc_si = softint_establish(SOFTINT_SERIAL, clpscom_soft, sc); 245 246 #ifdef RND_COM 247 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 248 RND_TYPE_TTY, RND_FLAG_DEFAULT); 249 #endif 250 251 SET(sc->sc_hwflags, COM_HW_DEV_OK); 252 } 253 254 static int 255 clpscom_txintr(void *arg) 256 { 257 struct clpscom_softc *sc = arg; 258 uint32_t sysflg; 259 260 if (!device_is_active(sc->sc_dev)) 261 return 0; 262 263 sysflg = CLPSCOM_READ_FLG(sc); 264 265 /* 266 * Done handling any receive interrupts. See if data can be 267 * transmitted as well. Schedule tx done event if no data left 268 * and tty was marked busy. 269 */ 270 271 if (!ISSET(sysflg, SYSFLG_UTXFF)) { 272 /* Output the next chunk of the contiguous buffer, if any. */ 273 if (sc->sc_tbc > 0) { 274 while (sc->sc_tbc > 0 && !ISSET(sysflg, SYSFLG_UTXFF)) { 275 CLPSCOM_WRITE(sc, *sc->sc_tba); 276 sc->sc_tba++; 277 sc->sc_tbc--; 278 sysflg = CLPSCOM_READ_FLG(sc); 279 } 280 } else if (!ISSET(sysflg, SYSFLG_UBUSY) && 281 sc->sc_ih[CLPSCOM_TXINT] != NULL) { 282 intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]); 283 sc->sc_ih[CLPSCOM_TXINT] = NULL; 284 sc->sc_tx_done = 1; 285 } 286 } 287 288 /* Wake up the poller. */ 289 softint_schedule(sc->sc_si); 290 291 return 1; 292 } 293 294 static int 295 clpscom_rxintr(void *arg) 296 { 297 struct clpscom_softc *sc = arg; 298 int cc; 299 uint32_t sysflg; 300 uint16_t data; 301 u_char *put; 302 303 if (!device_is_active(sc->sc_dev)) 304 return 0; 305 306 if (sc->sc_ih[CLPSCOM_RXINT] != NULL) { 307 put = sc->sc_rbput; 308 cc = sc->sc_rbavail; 309 while (cc > 0) { 310 sysflg = CLPSCOM_READ_FLG(sc); 311 if (ISSET(sysflg, SYSFLG_URXFE)) 312 break; 313 data = CLPSCOM_READ(sc); 314 cn_check_magic(sc->sc_tty->t_dev, data & 0xff, 315 clpscom_cnm_state); 316 317 put[0] = data & 0xff; 318 put[1] = (data >> 8) & 0xff; 319 put += 2; 320 if (put >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1)) 321 put = sc->sc_rbuf; 322 cc--; 323 sc->sc_rx_ready = 1; 324 } 325 326 /* 327 * Current string of incoming characters ended because 328 * no more data was available or we ran out of space. 329 * Schedule a receive event if any data was received. 330 * If we're out of space, turn off receive interrupts. 331 */ 332 sc->sc_rbput = put; 333 sc->sc_rbavail = cc; 334 335 /* 336 * See if we are in danger of overflowing a buffer. If 337 * so, use hardware flow control to ease the pressure. 338 */ 339 340 /* but clpscom cannot. X-( */ 341 342 /* 343 * If we're out of space, disable receive interrupts 344 * until the queue has drained a bit. 345 */ 346 if (cc <= 0) { 347 intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]); 348 sc->sc_ih[CLPSCOM_RXINT] = NULL; 349 } 350 } 351 352 /* Wake up the poller. */ 353 softint_schedule(sc->sc_si); 354 355 return 1; 356 } 357 358 static int 359 clpscom_msintr(void *arg) 360 { 361 struct clpscom_softc *sc = arg; 362 uint32_t ms, delta; 363 364 if (!device_is_active(sc->sc_dev)) 365 return 0; 366 367 if (sc->sc_ih[CLPSCOM_MSINT] != NULL) { 368 ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK; 369 delta = ms ^ sc->sc_ms; 370 sc->sc_ms = ms; 371 372 if (ISSET(delta, sc->sc_ms_mask)) { 373 SET(sc->sc_ms_delta, delta); 374 375 /* 376 * Stop output immediately if we lose the output 377 * flow control signal or carrier detect. 378 */ 379 if (ISSET(~ms, sc->sc_ms_mask)) 380 sc->sc_tbc = 0; 381 sc->sc_ms_changed = 1; 382 } 383 } 384 bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_UMSEOI, 1); 385 386 /* Wake up the poller. */ 387 softint_schedule(sc->sc_si); 388 389 return 1; 390 } 391 392 static void 393 clpscom_soft(void *arg) 394 { 395 struct clpscom_softc *sc = arg; 396 struct tty *tp = sc->sc_tty; 397 398 if (!device_is_active(sc->sc_dev)) 399 return; 400 401 if (sc->sc_rx_ready) { 402 sc->sc_rx_ready = 0; 403 clpscom_rxsoft(sc, tp); 404 } 405 if (sc->sc_tx_done) { 406 sc->sc_tx_done = 0; 407 CLR(tp->t_state, TS_BUSY); 408 if (ISSET(tp->t_state, TS_FLUSH)) 409 CLR(tp->t_state, TS_FLUSH); 410 else 411 ndflush(&tp->t_outq, 412 (int)(sc->sc_tba - tp->t_outq.c_cf)); 413 (*tp->t_linesw->l_start)(tp); 414 } 415 if (sc->sc_ms_changed == 1) { 416 sc->sc_ms_changed = 0; 417 clpscom_mssoft(sc, tp); 418 } 419 } 420 421 static void 422 clpscom_start(struct tty *tp) 423 { 424 struct clpscom_softc *sc 425 = device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev)); 426 int s, n; 427 428 if (!device_is_active(sc->sc_dev)) 429 return; 430 431 s = spltty(); 432 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 433 goto out; 434 if (sc->sc_tx_stopped) 435 goto out; 436 if (!ttypull(tp)) 437 goto out; 438 439 /* Grab the first contiguous region of buffer space. */ 440 { 441 u_char *tba; 442 int tbc; 443 444 tba = tp->t_outq.c_cf; 445 tbc = ndqb(&tp->t_outq, 0); 446 447 (void)splserial(); 448 449 sc->sc_tba = tba; 450 sc->sc_tbc = tbc; 451 } 452 453 SET(tp->t_state, TS_BUSY); 454 455 if (sc->sc_ih[CLPSCOM_TXINT] == NULL) { 456 sc->sc_ih[CLPSCOM_TXINT] = 457 intr_establish(sc->sc_irq[CLPSCOM_TXINT], IPL_SERIAL, 0, 458 clpscom_txintr, sc); 459 if (sc->sc_ih[CLPSCOM_TXINT] == NULL) 460 printf("%s: can't establish tx interrupt\n", 461 device_xname(sc->sc_dev)); 462 463 /* Output the first chunk of the contiguous buffer. */ 464 n = min(sc->sc_tbc, UART_FIFO_SIZE); 465 CLPSCOM_WRITE_MULTI(sc, sc->sc_tba, n); 466 sc->sc_tba += n; 467 sc->sc_tbc -= n; 468 } 469 out: 470 splx(s); 471 return; 472 } 473 474 static int 475 clpscom_param(struct tty *tp, struct termios *t) 476 { 477 struct clpscom_softc *sc = 478 device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev)); 479 int s; 480 481 if (!device_is_active(sc->sc_dev)) 482 return ENXIO; 483 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 484 return EINVAL; 485 486 /* 487 * For the console, always force CLOCAL and !HUPCL, so that the port 488 * is always active. 489 */ 490 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 491 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 492 SET(t->c_cflag, CLOCAL); 493 CLR(t->c_cflag, HUPCL); 494 } 495 496 /* 497 * If there were no changes, don't do anything. This avoids dropping 498 * input and improves performance when all we did was frob things like 499 * VMIN and VTIME. 500 */ 501 if (tp->t_ospeed == t->c_ospeed && 502 tp->t_cflag == t->c_cflag) 503 return 0; 504 505 /* 506 * If we're not in a mode that assumes a connection is present, then 507 * ignore carrier changes. 508 */ 509 if (ISSET(t->c_cflag, CLOCAL | MDMBUF)) 510 sc->sc_ms_dcd = 0; 511 else 512 sc->sc_ms_dcd = SYSFLG_DCD; 513 /* 514 * Set the flow control pins depending on the current flow control 515 * mode. 516 */ 517 if (ISSET(t->c_cflag, CRTSCTS)) { 518 sc->sc_ms_cts = SYSFLG_CTS; 519 } else if (ISSET(t->c_cflag, MDMBUF)) { 520 /* 521 * For DTR/DCD flow control, make sure we don't toggle DTR for 522 * carrier detection. 523 */ 524 sc->sc_ms_cts = SYSFLG_DCD; 525 } else { 526 /* 527 * If no flow control, then always set RTS. This will make 528 * the other side happy if it mistakenly thinks we're doing 529 * RTS/CTS flow control. 530 */ 531 sc->sc_ms_cts = 0; 532 } 533 sc->sc_ms_mask = sc->sc_ms_cts | sc->sc_ms_dcd; 534 535 s = splserial(); 536 CLPSCOM_WRITE_UBRLCR(sc, 537 UBRLCR_FIFOEN | 538 clpscom_rate2ubrlcr(t->c_ospeed) | 539 clpscom_cflag2ubrlcr(t->c_cflag)); 540 541 /* And copy to tty. */ 542 tp->t_ispeed = 0; 543 tp->t_ospeed = t->c_ospeed; 544 tp->t_cflag = t->c_cflag; 545 splx(s); 546 547 /* 548 * Update the tty layer's idea of the carrier bit, in case we changed 549 * CLOCAL or MDMBUF. We don't hang up here; we only do that by 550 * explicit request. 551 */ 552 (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_ms, SYSFLG_DCD)); 553 554 if (!ISSET(t->c_cflag, CHWFLOW)) 555 if (sc->sc_tx_stopped) { 556 sc->sc_tx_stopped = 0; 557 clpscom_start(tp); 558 } 559 560 return 0; 561 } 562 563 static int 564 clpscom_hwiflow(struct tty *tp, int block) 565 { 566 /* Nothing */ 567 return 0; 568 } 569 570 /* ARGSUSED */ 571 int 572 clpscomopen(dev_t dev, int flag, int mode, struct lwp *l) 573 { 574 struct clpscom_softc *sc; 575 struct tty *tp; 576 int error, s, s2; 577 578 sc = device_lookup_private(&clpscom_cd, COMUNIT(dev)); 579 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK)) 580 return ENXIO; 581 if (!device_is_active(sc->sc_dev)) 582 return ENXIO; 583 584 #ifdef KGDB 585 /* 586 * If this is the kgdb port, no other use is permitted. 587 */ 588 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 589 return EBUSY; 590 #endif 591 592 tp = sc->sc_tty; 593 594 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 595 return EBUSY; 596 597 s = spltty(); 598 599 /* 600 * Do the following iff this is a first open. 601 */ 602 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 603 struct termios t; 604 605 tp->t_dev = dev; 606 607 /* Enable and turn on interrupt */ 608 CLPSCOM_WRITE_CON(sc, CLPSCOM_READ_CON(sc) | SYSCON_UARTEN); 609 610 /* Fetch the current modem control status, needed later. */ 611 sc->sc_ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK; 612 613 /* 614 * Initialize the termios status to the defaults. Add in the 615 * sticky bits from TIOCSFLAGS. 616 */ 617 t.c_ispeed = 0; 618 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 619 t.c_ospeed = clpscom_cnrate; 620 t.c_cflag = clpscom_cncflag; 621 } else { 622 t.c_ospeed = TTYDEF_SPEED; 623 t.c_cflag = TTYDEF_CFLAG; 624 } 625 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 626 SET(t.c_cflag, CLOCAL); 627 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 628 SET(t.c_cflag, CRTSCTS); 629 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 630 SET(t.c_cflag, MDMBUF); 631 /* Make sure pscom_param() we do something */ 632 tp->t_ospeed = 0; 633 clpscom_param(tp, &t); 634 tp->t_iflag = TTYDEF_IFLAG; 635 tp->t_oflag = TTYDEF_OFLAG; 636 tp->t_lflag = TTYDEF_LFLAG; 637 ttychars(tp); 638 ttsetwater(tp); 639 640 s2 = splserial(); 641 642 /* Clear the input ring. */ 643 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 644 sc->sc_rbavail = CLPSCOM_RING_SIZE; 645 clpscom_iflush(sc); 646 647 splx(s2); 648 } 649 650 splx(s); 651 652 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 653 if (error) 654 goto bad; 655 656 error = (*tp->t_linesw->l_open)(dev, tp); 657 if (error) 658 goto bad; 659 return 0; 660 661 bad: 662 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 663 /* 664 * We failed to open the device, and nobody else had it opened. 665 * Clean up the state as appropriate. 666 */ 667 clpscom_shutdown(sc); 668 669 /* Disable UART */ 670 if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 671 CLPSCOM_WRITE_CON(sc, 672 CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN); 673 } 674 675 return error; 676 } 677 678 /* ARGSUSED */ 679 int 680 clpscomclose(dev_t dev, int flag, int mode, struct lwp *l) 681 { 682 struct clpscom_softc *sc = 683 device_lookup_private(&clpscom_cd, COMUNIT(dev)); 684 struct tty *tp = sc->sc_tty; 685 686 /* XXXX This is for cons.c. */ 687 if (!ISSET(tp->t_state, TS_ISOPEN)) 688 return 0; 689 690 (*tp->t_linesw->l_close)(tp, flag); 691 ttyclose(tp); 692 693 if (!device_is_active(sc->sc_dev)) 694 return 0; 695 696 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 697 /* 698 * Although we got a last close, the device may still be in 699 * use; e.g. if this was the dialout node, and there are still 700 * processes waiting for carrier on the non-dialout node. 701 */ 702 clpscom_shutdown(sc); 703 704 /* Disable UART */ 705 if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 706 CLPSCOM_WRITE_CON(sc, 707 CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN); 708 } 709 710 return 0; 711 } 712 713 int 714 clpscomread(dev_t dev, struct uio *uio, int flag) 715 { 716 struct clpscom_softc *sc = 717 device_lookup_private(&clpscom_cd, COMUNIT(dev)); 718 struct tty *tp = sc->sc_tty; 719 720 if (!device_is_active(sc->sc_dev)) 721 return EIO; 722 723 return (*tp->t_linesw->l_read)(tp, uio, flag); 724 } 725 726 int 727 clpscomwrite(dev_t dev, struct uio *uio, int flag) 728 { 729 struct clpscom_softc *sc = 730 device_lookup_private(&clpscom_cd, COMUNIT(dev)); 731 struct tty *tp = sc->sc_tty; 732 733 if (!device_is_active(sc->sc_dev)) 734 return EIO; 735 736 return (*tp->t_linesw->l_write)(tp, uio, flag); 737 } 738 739 int 740 clpscomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 741 { 742 struct clpscom_softc *sc = 743 device_lookup_private(&clpscom_cd, COMUNIT(dev)); 744 struct tty *tp = sc->sc_tty; 745 int error, s; 746 747 if (!device_is_active(sc->sc_dev)) 748 return EIO; 749 750 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 751 if (error != EPASSTHROUGH) 752 return error; 753 754 error = ttioctl(tp, cmd, data, flag, l); 755 if (error != EPASSTHROUGH) 756 return error; 757 758 switch (cmd) { 759 case TIOCSFLAGS: 760 error = kauth_authorize_device_tty(l->l_cred, 761 KAUTH_DEVICE_TTY_PRIVSET, tp); 762 break; 763 default: 764 break; 765 } 766 if (error) 767 return error; 768 769 s = splserial(); 770 error = 0; 771 switch (cmd) { 772 case TIOCSBRK: 773 clpscom_break(sc, 1); 774 break; 775 776 case TIOCCBRK: 777 clpscom_break(sc, 0); 778 break; 779 780 case TIOCGFLAGS: 781 *(int *)data = sc->sc_swflags; 782 break; 783 784 case TIOCSFLAGS: 785 sc->sc_swflags = *(int *)data; 786 break; 787 788 case TIOCMGET: 789 *(int *)data = clpscom_to_tiocm(sc); 790 break; 791 792 default: 793 error = EPASSTHROUGH; 794 break; 795 } 796 splx(s); 797 return error; 798 } 799 800 int 801 clpscompoll(dev_t dev, int events, struct lwp *l) 802 { 803 struct clpscom_softc *sc = 804 device_lookup_private(&clpscom_cd, COMUNIT(dev)); 805 struct tty *tp = sc->sc_tty; 806 807 if (!device_is_active(sc->sc_dev)) 808 return EIO; 809 810 return (*tp->t_linesw->l_poll)(tp, events, l); 811 } 812 813 struct tty * 814 clpscomtty(dev_t dev) 815 { 816 struct clpscom_softc *sc = 817 device_lookup_private(&clpscom_cd, COMUNIT(dev)); 818 819 return sc->sc_tty; 820 } 821 822 void 823 clpscomstop(struct tty *tp, int flag) 824 { 825 int s; 826 827 s = splserial(); 828 if (ISSET(tp->t_state, TS_BUSY)) { 829 /* Stop transmitting at the next chunk. */ 830 if (!ISSET(tp->t_state, TS_TTSTOP)) 831 SET(tp->t_state, TS_FLUSH); 832 } 833 splx(s); 834 } 835 836 837 static void 838 clpscom_iflush(struct clpscom_softc *sc) 839 { 840 int timo; 841 842 timo = 50000; 843 while ((CLPSCOM_READ_FLG(sc) & SYSFLG_URXFE) == 0 844 && timo--) 845 CLPSCOM_READ(sc); 846 if (timo == 0) 847 printf("%s: iflush timeout\n", device_xname(sc->sc_dev)); 848 } 849 850 static void 851 clpscom_shutdown(struct clpscom_softc *sc) 852 { 853 int s; 854 855 s = splserial(); 856 857 /* Turn off all interrupts */ 858 if (sc->sc_ih[CLPSCOM_TXINT] != NULL) 859 intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]); 860 sc->sc_ih[CLPSCOM_TXINT] = NULL; 861 if (sc->sc_ih[CLPSCOM_RXINT] != NULL) 862 intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]); 863 sc->sc_ih[CLPSCOM_RXINT] = NULL; 864 if (sc->sc_ih[CLPSCOM_MSINT] != NULL) 865 intr_disestablish(sc->sc_ih[CLPSCOM_MSINT]); 866 sc->sc_ih[CLPSCOM_MSINT] = NULL; 867 868 /* Clear any break condition set with TIOCSBRK. */ 869 clpscom_break(sc, 0); 870 871 splx(s); 872 } 873 874 static void 875 clpscom_break(struct clpscom_softc *sc, int onoff) 876 { 877 int s; 878 uint8_t ubrlcr; 879 880 s = splserial(); 881 ubrlcr = CLPSCOM_READ_UBRLCR(sc); 882 if (onoff) 883 SET(ubrlcr, UBRLCR_BREAK); 884 else 885 CLR(ubrlcr, UBRLCR_BREAK); 886 CLPSCOM_WRITE_UBRLCR(sc, ubrlcr); 887 splx(s); 888 } 889 890 static int 891 clpscom_to_tiocm(struct clpscom_softc *sc) 892 { 893 uint32_t combits; 894 int ttybits = 0; 895 896 combits = sc->sc_ms; 897 if (ISSET(combits, SYSFLG_DCD)) 898 SET(ttybits, TIOCM_CD); 899 if (ISSET(combits, SYSFLG_CTS)) 900 SET(ttybits, TIOCM_CTS); 901 if (ISSET(combits, SYSFLG_DSR)) 902 SET(ttybits, TIOCM_DSR); 903 904 return ttybits; 905 } 906 907 static void 908 clpscom_rxsoft(struct clpscom_softc *sc, struct tty *tp) 909 { 910 int code, s; 911 u_int cc, scc; 912 u_char sts, *get; 913 914 get = sc->sc_rbget; 915 scc = cc = CLPSCOM_RING_SIZE - sc->sc_rbavail; 916 while (cc) { 917 code = get[0]; 918 sts = get[1]; 919 if (ISSET(sts, UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)) { 920 if (ISSET(sts, (UARTDR_FRMERR))) 921 SET(code, TTY_FE); 922 if (ISSET(sts, UARTDR_PARERR)) 923 SET(code, TTY_PE); 924 if (ISSET(sts, UARTDR_OVERR)) 925 ; /* XXXXX: Overrun */ 926 } 927 if ((*tp->t_linesw->l_rint)(code, tp) == -1) { 928 /* 929 * The line discipline's buffer is out of space. 930 */ 931 /* 932 * We're either not using flow control, or the 933 * line discipline didn't tell us to block for 934 * some reason. Either way, we have no way to 935 * know when there's more space available, so 936 * just drop the rest of the data. 937 */ 938 get += cc << 1; 939 if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1)) 940 get -= (CLPSCOM_RING_SIZE << 1); 941 cc = 0; 942 break; 943 } 944 get += 2; 945 if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1)) 946 get = sc->sc_rbuf; 947 cc--; 948 } 949 950 if (cc != scc) { 951 sc->sc_rbget = get; 952 s = splserial(); 953 954 cc = sc->sc_rbavail += scc - cc; 955 /* Buffers should be ok again, release possible block. */ 956 if (cc >= 1) { 957 if (sc->sc_ih[CLPSCOM_RXINT] == NULL) { 958 sc->sc_ih[CLPSCOM_RXINT] = 959 intr_establish(sc->sc_irq[CLPSCOM_RXINT], 960 IPL_SERIAL, 0, clpscom_rxintr, sc); 961 if (sc->sc_ih[CLPSCOM_RXINT] == NULL) 962 printf("%s: can't establish" 963 " rx interrupt\n", 964 device_xname(sc->sc_dev)); 965 } 966 if (sc->sc_ih[CLPSCOM_MSINT] == NULL) { 967 sc->sc_ih[CLPSCOM_MSINT] = 968 intr_establish(sc->sc_irq[CLPSCOM_MSINT], 969 IPL_SERIAL, 0, clpscom_msintr, sc); 970 if (sc->sc_ih[CLPSCOM_MSINT] == NULL) 971 printf("%s: can't establish" 972 " ms interrupt\n", 973 device_xname(sc->sc_dev)); 974 } 975 } 976 splx(s); 977 } 978 } 979 980 static void 981 clpscom_mssoft(struct clpscom_softc *sc, struct tty *tp) 982 { 983 uint32_t ms, delta; 984 985 ms = sc->sc_ms; 986 delta = sc->sc_ms_delta; 987 sc->sc_ms_delta = 0; 988 989 if (ISSET(delta, sc->sc_ms_dcd)) 990 /* 991 * Inform the tty layer that carrier detect changed. 992 */ 993 (void) (*tp->t_linesw->l_modem)(tp, ISSET(ms, SYSFLG_DCD)); 994 995 if (ISSET(delta, sc->sc_ms_cts)) { 996 /* Block or unblock output according to flow control. */ 997 if (ISSET(ms, sc->sc_ms_cts)) { 998 sc->sc_tx_stopped = 0; 999 (*tp->t_linesw->l_start)(tp); 1000 } else 1001 sc->sc_tx_stopped = 1; 1002 } 1003 } 1004 1005 static inline uint32_t 1006 clpscom_rate2ubrlcr(int rate) 1007 { 1008 1009 return 230400 / rate - 1; 1010 } 1011 1012 static uint32_t 1013 clpscom_cflag2ubrlcr(tcflag_t cflag) 1014 { 1015 int32_t ubrlcr = 0; 1016 1017 switch (cflag & CSIZE) { 1018 case CS5: SET(ubrlcr, UBRLCR_WRDLEN_5B); break; 1019 case CS6: SET(ubrlcr, UBRLCR_WRDLEN_6B); break; 1020 case CS7: SET(ubrlcr, UBRLCR_WRDLEN_7B); break; 1021 case CS8: SET(ubrlcr, UBRLCR_WRDLEN_8B); break; 1022 default: SET(ubrlcr, UBRLCR_WRDLEN_8B); break; 1023 } 1024 if (cflag & CSTOPB) 1025 SET(ubrlcr, UBRLCR_XSTOP); 1026 if (cflag & PARENB) { 1027 SET(ubrlcr, (UBRLCR_PRTEN | UBRLCR_EVENPRT)); 1028 if (cflag & PARODD) 1029 CLR(ubrlcr, UBRLCR_EVENPRT); 1030 } 1031 return ubrlcr; 1032 } 1033 1034 #define CLPSCOM_CNREAD() \ 1035 (*(volatile uint32_t *)(clpscom_cnaddr + PS711X_UARTDR)) 1036 #define CLPSCOM_CNWRITE(val) \ 1037 (*(volatile uint8_t *)(clpscom_cnaddr + PS711X_UARTDR) = val) 1038 #define CLPSCOM_CNSTATUS() \ 1039 (*(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG)) 1040 1041 static struct consdev clpscomcons = { 1042 NULL, NULL, clpscom_cngetc, clpscom_cnputc, clpscom_cnpollc, 1043 NULL, NULL, NULL, NODEV, CN_NORMAL 1044 }; 1045 1046 int 1047 clpscom_cnattach(vaddr_t addr, int rate, tcflag_t cflag) 1048 { 1049 1050 clpscom_cnaddr = addr; 1051 clpscom_cnrate = rate; 1052 clpscom_cncflag = cflag; 1053 *(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG) |= SYSCON_UARTEN; 1054 *(volatile uint32_t *)(clpscom_cnaddr + PS711X_UBRLCR) = 1055 UBRLCR_FIFOEN | 1056 clpscom_cflag2ubrlcr(cflag) | 1057 clpscom_rate2ubrlcr(rate); 1058 1059 cn_tab = &clpscomcons; 1060 cn_init_magic(&clpscom_cnm_state); 1061 cn_set_magic("\047\001"); /* default magic is BREAK */ 1062 1063 return 0; 1064 } 1065 1066 /* ARGSUSED */ 1067 static int 1068 clpscom_cngetc(dev_t dev) 1069 { 1070 int s = splserial(); 1071 char ch; 1072 1073 while (CLPSCOM_CNSTATUS() & SYSFLG_URXFE); 1074 1075 ch = CLPSCOM_CNREAD(); 1076 1077 { 1078 #ifdef DDB 1079 extern int db_active; 1080 if (!db_active) 1081 #endif 1082 cn_check_magic(dev, ch, clpscom_cnm_state); 1083 } 1084 1085 splx(s); 1086 return ch; 1087 } 1088 1089 /* ARGSUSED */ 1090 static void 1091 clpscom_cnputc(dev_t dev, int c) 1092 { 1093 int s = splserial(); 1094 1095 while (CLPSCOM_CNSTATUS() & SYSFLG_UTXFF); 1096 1097 CLPSCOM_CNWRITE(c); 1098 1099 /* Make sure output. */ 1100 while (CLPSCOM_CNSTATUS() & SYSFLG_UBUSY); 1101 1102 splx(s); 1103 } 1104 1105 /* ARGSUSED */ 1106 static void 1107 clpscom_cnpollc(dev_t dev, int on) 1108 { 1109 /* Nothing */ 1110 } 1111