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