1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2003 Marcel Moolenaar 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/bus.h> 32 #include <sys/conf.h> 33 #include <sys/cons.h> 34 #include <sys/fcntl.h> 35 #include <sys/interrupt.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/reboot.h> 39 #include <machine/bus.h> 40 #include <sys/rman.h> 41 #include <sys/tty.h> 42 #include <machine/resource.h> 43 #include <machine/stdarg.h> 44 45 #include <dev/uart/uart.h> 46 #include <dev/uart/uart_bus.h> 47 #include <dev/uart/uart_cpu.h> 48 49 #include "uart_if.h" 50 51 static cn_probe_t uart_cnprobe; 52 static cn_init_t uart_cninit; 53 static cn_init_t uart_cnresume; 54 static cn_term_t uart_cnterm; 55 static cn_getc_t uart_cngetc; 56 static cn_putc_t uart_cnputc; 57 static cn_grab_t uart_cngrab; 58 static cn_ungrab_t uart_cnungrab; 59 60 static tsw_open_t uart_tty_open; 61 static tsw_close_t uart_tty_close; 62 static tsw_outwakeup_t uart_tty_outwakeup; 63 static tsw_inwakeup_t uart_tty_inwakeup; 64 static tsw_ioctl_t uart_tty_ioctl; 65 static tsw_param_t uart_tty_param; 66 static tsw_modem_t uart_tty_modem; 67 static tsw_free_t uart_tty_free; 68 static tsw_busy_t uart_tty_busy; 69 70 CONSOLE_DRIVER( 71 uart, 72 .cn_resume = uart_cnresume, 73 ); 74 75 static struct uart_devinfo uart_console; 76 77 /* TTY swi(9) event. Allows all uart soft handlers to share one ithread. */ 78 static struct intr_event *tty_intr_event; 79 80 static void 81 uart_cnprobe(struct consdev *cp) 82 { 83 84 cp->cn_pri = CN_DEAD; 85 86 KASSERT(uart_console.cookie == NULL, ("foo")); 87 88 if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console)) 89 return; 90 91 if (uart_probe(&uart_console)) 92 return; 93 94 strlcpy(cp->cn_name, uart_driver_name, sizeof(cp->cn_name)); 95 cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; 96 cp->cn_arg = &uart_console; 97 } 98 99 static void 100 uart_cninit(struct consdev *cp) 101 { 102 struct uart_devinfo *di; 103 104 /* 105 * Yedi trick: we need to be able to define cn_dev before we go 106 * single- or multi-user. The problem is that we don't know at 107 * this time what the device will be. Hence, we need to link from 108 * the uart_devinfo to the consdev that corresponds to it so that 109 * we can define cn_dev in uart_bus_attach() when we find the 110 * device during bus enumeration. That's when we'll know what the 111 * the unit number will be. 112 */ 113 di = cp->cn_arg; 114 KASSERT(di->cookie == NULL, ("foo")); 115 di->cookie = cp; 116 di->type = UART_DEV_CONSOLE; 117 uart_add_sysdev(di); 118 uart_init(di); 119 } 120 121 static void 122 uart_cnresume(struct consdev *cp) 123 { 124 125 uart_init(cp->cn_arg); 126 } 127 128 static void 129 uart_cnterm(struct consdev *cp) 130 { 131 132 uart_term(cp->cn_arg); 133 } 134 135 static void 136 uart_cngrab(struct consdev *cp) 137 { 138 139 uart_grab(cp->cn_arg); 140 } 141 142 static void 143 uart_cnungrab(struct consdev *cp) 144 { 145 146 uart_ungrab(cp->cn_arg); 147 } 148 149 static void 150 uart_cnputc(struct consdev *cp, int c) 151 { 152 153 uart_putc(cp->cn_arg, c); 154 } 155 156 static int 157 uart_cngetc(struct consdev *cp) 158 { 159 160 return (uart_poll(cp->cn_arg)); 161 } 162 163 static int 164 uart_tty_open(struct tty *tp) 165 { 166 struct uart_softc *sc; 167 168 sc = tty_softc(tp); 169 170 if (sc == NULL || sc->sc_leaving) 171 return (ENXIO); 172 173 sc->sc_opened = 1; 174 return (0); 175 } 176 177 static void 178 uart_tty_close(struct tty *tp) 179 { 180 struct uart_softc *sc; 181 182 sc = tty_softc(tp); 183 if (sc == NULL || sc->sc_leaving || !sc->sc_opened) 184 return; 185 186 if (sc->sc_hwiflow) 187 UART_IOCTL(sc, UART_IOCTL_IFLOW, 0); 188 if (sc->sc_hwoflow) 189 UART_IOCTL(sc, UART_IOCTL_OFLOW, 0); 190 if (sc->sc_sysdev == NULL) 191 UART_SETSIG(sc, SER_DDTR | SER_DRTS); 192 193 wakeup(sc); 194 sc->sc_opened = 0; 195 } 196 197 static void 198 uart_tty_outwakeup(struct tty *tp) 199 { 200 struct uart_softc *sc; 201 202 sc = tty_softc(tp); 203 if (sc == NULL || sc->sc_leaving) 204 return; 205 206 if (sc->sc_txbusy) 207 return; 208 209 /* 210 * Respect RTS/CTS (output) flow control if enabled and not already 211 * handled by hardware. 212 */ 213 if ((tp->t_termios.c_cflag & CCTS_OFLOW) && !sc->sc_hwoflow && 214 !(sc->sc_hwsig & SER_CTS)) 215 return; 216 217 sc->sc_txdatasz = ttydisc_getc(tp, sc->sc_txbuf, sc->sc_txfifosz); 218 if (sc->sc_txdatasz != 0) 219 UART_TRANSMIT(sc); 220 } 221 222 static void 223 uart_tty_inwakeup(struct tty *tp) 224 { 225 struct uart_softc *sc; 226 227 sc = tty_softc(tp); 228 if (sc == NULL || sc->sc_leaving) 229 return; 230 231 if (sc->sc_isquelch) { 232 if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) 233 UART_SETSIG(sc, SER_DRTS|SER_RTS); 234 sc->sc_isquelch = 0; 235 uart_sched_softih(sc, SER_INT_RXREADY); 236 } 237 } 238 239 static int 240 uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data, 241 struct thread *td __unused) 242 { 243 struct uart_softc *sc; 244 245 sc = tty_softc(tp); 246 247 switch (cmd) { 248 case TIOCSBRK: 249 UART_IOCTL(sc, UART_IOCTL_BREAK, 1); 250 return (0); 251 case TIOCCBRK: 252 UART_IOCTL(sc, UART_IOCTL_BREAK, 0); 253 return (0); 254 default: 255 return pps_ioctl(cmd, data, &sc->sc_pps); 256 } 257 } 258 259 static int 260 uart_tty_param(struct tty *tp, struct termios *t) 261 { 262 struct uart_softc *sc; 263 int databits, parity, stopbits; 264 265 sc = tty_softc(tp); 266 if (sc == NULL || sc->sc_leaving) 267 return (ENODEV); 268 if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0) 269 return (EINVAL); 270 if (t->c_ospeed == 0) { 271 UART_SETSIG(sc, SER_DDTR | SER_DRTS); 272 return (0); 273 } 274 switch (t->c_cflag & CSIZE) { 275 case CS5: databits = 5; break; 276 case CS6: databits = 6; break; 277 case CS7: databits = 7; break; 278 default: databits = 8; break; 279 } 280 stopbits = (t->c_cflag & CSTOPB) ? 2 : 1; 281 if (t->c_cflag & PARENB) 282 parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD : 283 UART_PARITY_EVEN; 284 else 285 parity = UART_PARITY_NONE; 286 if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0) 287 return (EINVAL); 288 if ((t->c_cflag & CNO_RTSDTR) == 0) 289 UART_SETSIG(sc, SER_DDTR | SER_DTR); 290 /* Set input flow control state. */ 291 if (!sc->sc_hwiflow) { 292 if ((t->c_cflag & CRTS_IFLOW) && sc->sc_isquelch) 293 UART_SETSIG(sc, SER_DRTS); 294 else { 295 if ((t->c_cflag & CNO_RTSDTR) == 0) 296 UART_SETSIG(sc, SER_DRTS | SER_RTS); 297 } 298 } else 299 UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW)); 300 /* Set output flow control state. */ 301 if (sc->sc_hwoflow) 302 UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW)); 303 304 return (0); 305 } 306 307 static int 308 uart_tty_modem(struct tty *tp, int biton, int bitoff) 309 { 310 struct uart_softc *sc; 311 312 sc = tty_softc(tp); 313 if (biton != 0 || bitoff != 0) 314 UART_SETSIG(sc, SER_DELTA(bitoff | biton) | biton); 315 return (sc->sc_hwsig); 316 } 317 318 void 319 uart_tty_intr(void *arg) 320 { 321 struct uart_softc *sc = arg; 322 struct tty *tp; 323 int c, err = 0, pend, sig, xc; 324 325 if (sc->sc_leaving) 326 return; 327 328 pend = atomic_readandclear_32(&sc->sc_ttypend); 329 if (!(pend & SER_INT_MASK)) 330 return; 331 332 tp = sc->sc_u.u_tty.tp; 333 tty_lock(tp); 334 335 if (pend & SER_INT_RXREADY) { 336 while (!uart_rx_empty(sc) && !sc->sc_isquelch) { 337 xc = uart_rx_peek(sc); 338 c = xc & 0xff; 339 if (xc & UART_STAT_FRAMERR) 340 err |= TRE_FRAMING; 341 if (xc & UART_STAT_OVERRUN) 342 err |= TRE_OVERRUN; 343 if (xc & UART_STAT_PARERR) 344 err |= TRE_PARITY; 345 if (ttydisc_rint(tp, c, err) != 0) { 346 sc->sc_isquelch = 1; 347 if ((tp->t_termios.c_cflag & CRTS_IFLOW) && 348 !sc->sc_hwiflow) 349 UART_SETSIG(sc, SER_DRTS); 350 } else 351 uart_rx_next(sc); 352 } 353 } 354 355 if (pend & SER_INT_BREAK) 356 ttydisc_rint(tp, 0, TRE_BREAK); 357 358 if (pend & SER_INT_SIGCHG) { 359 sig = pend & SER_INT_SIGMASK; 360 if (sig & SER_DDCD) 361 ttydisc_modem(tp, sig & SER_DCD); 362 if (sig & SER_DCTS) 363 uart_tty_outwakeup(tp); 364 } 365 366 if (pend & SER_INT_TXIDLE) 367 uart_tty_outwakeup(tp); 368 ttydisc_rint_done(tp); 369 tty_unlock(tp); 370 } 371 372 static void 373 uart_tty_free(void *arg __unused) 374 { 375 376 /* 377 * XXX: uart(4) could reuse the device unit number before it is 378 * being freed by the TTY layer. We should use this hook to free 379 * the device unit number, but unfortunately newbus does not 380 * seem to support such a construct. 381 */ 382 } 383 384 static bool 385 uart_tty_busy(struct tty *tp) 386 { 387 struct uart_softc *sc; 388 389 sc = tty_softc(tp); 390 if (sc == NULL || sc->sc_leaving) 391 return (FALSE); 392 393 return (sc->sc_txbusy); 394 } 395 396 static struct ttydevsw uart_tty_class = { 397 .tsw_flags = TF_INITLOCK|TF_CALLOUT, 398 .tsw_open = uart_tty_open, 399 .tsw_close = uart_tty_close, 400 .tsw_outwakeup = uart_tty_outwakeup, 401 .tsw_inwakeup = uart_tty_inwakeup, 402 .tsw_ioctl = uart_tty_ioctl, 403 .tsw_param = uart_tty_param, 404 .tsw_modem = uart_tty_modem, 405 .tsw_free = uart_tty_free, 406 .tsw_busy = uart_tty_busy, 407 }; 408 409 int 410 uart_tty_attach(struct uart_softc *sc) 411 { 412 struct tty *tp; 413 int unit; 414 415 sc->sc_u.u_tty.tp = tp = tty_alloc(&uart_tty_class, sc); 416 417 unit = device_get_unit(sc->sc_dev); 418 419 if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 420 sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name, 421 "ttyu%r", unit); 422 tty_init_console(tp, sc->sc_sysdev->baudrate); 423 } 424 425 swi_add(&tty_intr_event, uart_driver_name, uart_tty_intr, sc, SWI_TTY, 426 INTR_TYPE_TTY, &sc->sc_softih); 427 428 tty_makedev(tp, NULL, "u%r", unit); 429 430 return (0); 431 } 432 433 int 434 uart_tty_detach(struct uart_softc *sc) 435 { 436 struct tty *tp; 437 438 tp = sc->sc_u.u_tty.tp; 439 440 tty_lock(tp); 441 swi_remove(sc->sc_softih); 442 tty_rel_gone(tp); 443 444 return (0); 445 } 446 447 struct mtx * 448 uart_tty_getlock(struct uart_softc *sc) 449 { 450 451 if (sc->sc_u.u_tty.tp != NULL) 452 return (tty_getlock(sc->sc_u.u_tty.tp)); 453 else 454 return (NULL); 455 } 456