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