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