1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/bus.h> 35#include <sys/conf.h> 36#include <sys/cons.h> 37#include <sys/fcntl.h> 38#include <sys/interrupt.h> 39#include <sys/kernel.h> 40#include <sys/malloc.h> 41#include <sys/reboot.h> 42#include <machine/bus.h> 43#include <sys/rman.h> 44#include <sys/tty.h> 45#include <machine/resource.h> 46#include <machine/stdarg.h> 47 48#include <dev/uart/uart.h> 49#include <dev/uart/uart_bus.h> 50#include <dev/uart/uart_cpu.h> 51 52#include "uart_if.h" 53 54static cn_probe_t uart_cnprobe; 55static cn_init_t uart_cninit; 56static cn_init_t uart_cnresume; 57static cn_term_t uart_cnterm; 58static cn_getc_t uart_cngetc; 59static cn_putc_t uart_cnputc; 60static cn_grab_t uart_cngrab; 61static cn_ungrab_t uart_cnungrab; 62 63static tsw_open_t uart_tty_open; 64static tsw_close_t uart_tty_close; 65static tsw_outwakeup_t uart_tty_outwakeup; 66static tsw_inwakeup_t uart_tty_inwakeup; 67static tsw_ioctl_t uart_tty_ioctl; 68static tsw_param_t uart_tty_param; 69static tsw_modem_t uart_tty_modem; 70static tsw_free_t uart_tty_free; 71static tsw_busy_t uart_tty_busy; 72 73CONSOLE_DRIVER( 74 uart, 75 .cn_resume = uart_cnresume, 76); 77 78static struct uart_devinfo uart_console; 79 80static void 81uart_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 99static void 100uart_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 121static void 122uart_cnresume(struct consdev *cp) 123{ 124 125 uart_init(cp->cn_arg); 126} 127 128static void 129uart_cnterm(struct consdev *cp) 130{ 131 132 uart_term(cp->cn_arg); 133} 134 135static void 136uart_cngrab(struct consdev *cp) 137{ 138 139 uart_grab(cp->cn_arg); 140} 141 142static void 143uart_cnungrab(struct consdev *cp) 144{ 145 146 uart_ungrab(cp->cn_arg); 147} 148 149static void 150uart_cnputc(struct consdev *cp, int c) 151{ 152 153 uart_putc(cp->cn_arg, c); 154} 155 156static int 157uart_cngetc(struct consdev *cp) 158{ 159 160 return (uart_poll(cp->cn_arg)); 161} 162 163static int 164uart_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 177static void 178uart_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 197static void 198uart_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 222static void 223uart_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 239static int 240uart_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 259static int 260uart_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 307static int 308uart_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 318void 319uart_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 372static void 373uart_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 384static bool 385uart_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 396static 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 409int 410uart_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 433int 434uart_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 447struct mtx * 448uart_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