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