1/* $OpenBSD: exuart.c,v 1.12 2023/07/23 11:16:36 kettenis Exp $ */ 2/* 3 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <sys/param.h> 19#include <sys/ioctl.h> 20#include <sys/proc.h> 21#include <sys/tty.h> 22#include <sys/uio.h> 23#include <sys/systm.h> 24#include <sys/time.h> 25#include <sys/device.h> 26#include <sys/syslog.h> 27#include <sys/conf.h> 28#include <sys/fcntl.h> 29#include <sys/kernel.h> 30 31#include <machine/bus.h> 32#include <machine/fdt.h> 33 34#include <dev/cons.h> 35 36#ifdef DDB 37#include <ddb/db_var.h> 38#endif 39 40#include <dev/fdt/exuartreg.h> 41 42#include <dev/ofw/openfirm.h> 43#include <dev/ofw/ofw_power.h> 44#include <dev/ofw/fdt.h> 45 46#define DEVUNIT(x) (minor(x) & 0x7f) 47#define DEVCUA(x) (minor(x) & 0x80) 48 49struct exuart_softc { 50 struct device sc_dev; 51 bus_space_tag_t sc_iot; 52 bus_space_handle_t sc_ioh; 53 struct soft_intrhand *sc_si; 54 void *sc_irq; 55 struct tty *sc_tty; 56 struct timeout sc_diag_tmo; 57 struct timeout sc_dtr_tmo; 58 59 uint32_t sc_rx_fifo_cnt_mask; 60 uint32_t sc_rx_fifo_full; 61 uint32_t sc_tx_fifo_full; 62 int sc_type; 63#define EXUART_TYPE_EXYNOS 0 64#define EXUART_TYPE_S5L 1 65 66 int sc_fifo; 67 int sc_overflows; 68 int sc_floods; 69 int sc_errors; 70 int sc_halt; 71 u_int32_t sc_ulcon; 72 u_int32_t sc_ucon; 73 u_int32_t sc_ufcon; 74 u_int32_t sc_umcon; 75 u_int32_t sc_uintm; 76 u_int8_t sc_hwflags; 77#define COM_HW_NOIEN 0x01 78#define COM_HW_FIFO 0x02 79#define COM_HW_SIR 0x20 80#define COM_HW_CONSOLE 0x40 81 u_int8_t sc_swflags; 82#define COM_SW_SOFTCAR 0x01 83#define COM_SW_CLOCAL 0x02 84#define COM_SW_CRTSCTS 0x04 85#define COM_SW_MDMBUF 0x08 86#define COM_SW_PPS 0x10 87 88 u_int8_t sc_initialize; 89 u_int8_t sc_cua; 90 u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; 91#define EXUART_IBUFSIZE 128 92#define EXUART_IHIGHWATER 100 93 u_int16_t sc_ibufs[2][EXUART_IBUFSIZE]; 94}; 95 96 97int exuart_match(struct device *, void *, void *); 98void exuart_attach(struct device *, struct device *, void *); 99 100void exuartcnprobe(struct consdev *cp); 101void exuartcninit(struct consdev *cp); 102int exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, 103 tcflag_t cflag); 104int exuartcngetc(dev_t dev); 105void exuartcnputc(dev_t dev, int c); 106void exuartcnpollc(dev_t dev, int on); 107int exuart_param(struct tty *tp, struct termios *t); 108void exuart_start(struct tty *); 109void exuart_diag(void *arg); 110void exuart_raisedtr(void *arg); 111void exuart_softint(void *arg); 112struct exuart_softc *exuart_sc(dev_t dev); 113 114int exuart_intr(void *); 115int exuart_s5l_intr(void *); 116 117/* XXX - we imitate 'com' serial ports and take over their entry points */ 118/* XXX: These belong elsewhere */ 119cdev_decl(com); 120cdev_decl(exuart); 121 122struct cfdriver exuart_cd = { 123 NULL, "exuart", DV_TTY 124}; 125 126const struct cfattach exuart_ca = { 127 sizeof(struct exuart_softc), exuart_match, exuart_attach 128}; 129 130bus_space_tag_t exuartconsiot; 131bus_space_handle_t exuartconsioh; 132bus_addr_t exuartconsaddr; 133tcflag_t exuartconscflag = TTYDEF_CFLAG; 134int exuartdefaultrate = B115200; 135 136uint32_t exuart_rx_fifo_cnt_mask; 137uint32_t exuart_rx_fifo_full; 138uint32_t exuart_tx_fifo_full; 139 140struct cdevsw exuartdev = 141 cdev_tty_init(3/*XXX NEXUART */ ,exuart); /* 12: serial port */ 142 143void 144exuart_init_cons(void) 145{ 146 struct fdt_reg reg; 147 void *node, *root; 148 149 if ((node = fdt_find_cons("apple,s5l-uart")) == NULL && 150 (node = fdt_find_cons("samsung,exynos4210-uart")) == NULL) 151 return; 152 153 /* dtb uses serial2, qemu uses serial0 */ 154 root = fdt_find_node("/"); 155 if (root == NULL) 156 panic("%s: could not get fdt root node", __func__); 157 if (fdt_is_compatible(root, "samsung,universal_c210")) { 158 if ((node = fdt_find_node("/serial@13800000")) == NULL) { 159 return; 160 } 161 stdout_node = OF_finddevice("/serial@13800000"); 162 } 163 164 if (fdt_get_reg(node, 0, ®)) 165 return; 166 167 if (fdt_is_compatible(node, "apple,s5l-uart")) { 168 exuart_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK; 169 exuart_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL; 170 exuart_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL; 171 } else { 172 exuart_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK; 173 exuart_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL; 174 exuart_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL; 175 } 176 177 exuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG); 178} 179 180int 181exuart_match(struct device *parent, void *self, void *aux) 182{ 183 struct fdt_attach_args *faa = aux; 184 185 return (OF_is_compatible(faa->fa_node, "apple,s5l-uart") || 186 OF_is_compatible(faa->fa_node, "samsung,exynos4210-uart")); 187} 188 189void 190exuart_attach(struct device *parent, struct device *self, void *aux) 191{ 192 struct exuart_softc *sc = (struct exuart_softc *) self; 193 struct fdt_attach_args *faa = aux; 194 int maj; 195 196 if (faa->fa_nreg < 1) 197 return; 198 199 sc->sc_iot = faa->fa_iot; 200 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size, 201 0, &sc->sc_ioh)) 202 panic("%s: bus_space_map failed!", __func__); 203 204 if (stdout_node == faa->fa_node) { 205 /* Locate the major number. */ 206 for (maj = 0; maj < nchrdev; maj++) 207 if (cdevsw[maj].d_open == exuartopen) 208 break; 209 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 210 211 printf(": console"); 212 } 213 214 printf("\n"); 215 216 power_domain_enable(faa->fa_node); 217 218 if (OF_is_compatible(faa->fa_node, "apple,s5l-uart")) { 219 sc->sc_type = EXUART_TYPE_S5L; 220 sc->sc_rx_fifo_cnt_mask = EXUART_S5L_UFSTAT_RX_FIFO_CNT_MASK; 221 sc->sc_rx_fifo_full = EXUART_S5L_UFSTAT_RX_FIFO_FULL; 222 sc->sc_tx_fifo_full = EXUART_S5L_UFSTAT_TX_FIFO_FULL; 223 224 /* Mask and clear interrupts. */ 225 sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 226 EXUART_UCON); 227 CLR(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT); 228 CLR(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH); 229 CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH); 230 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON, 231 sc->sc_ucon); 232 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UTRSTAT, 233 EXUART_S5L_UTRSTAT_RX_TIMEOUT | 234 EXUART_S5L_UTRSTAT_RXTHRESH | 235 EXUART_S5L_UTRSTAT_TXTHRESH); 236 237 sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 238 EXUART_UCON); 239 SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT); 240 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON, 241 sc->sc_ucon); 242 243 sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY, 244 exuart_s5l_intr, sc, sc->sc_dev.dv_xname); 245 } else { 246 sc->sc_type = EXUART_TYPE_EXYNOS; 247 sc->sc_rx_fifo_cnt_mask = EXUART_UFSTAT_RX_FIFO_CNT_MASK; 248 sc->sc_rx_fifo_full = EXUART_UFSTAT_RX_FIFO_FULL; 249 sc->sc_tx_fifo_full = EXUART_UFSTAT_TX_FIFO_FULL; 250 251 /* Mask and clear interrupts. */ 252 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTM, 253 EXUART_UINTM_RXD | EXUART_UINTM_ERROR | 254 EXUART_UINTM_TXD | EXUART_UINTM_MODEM); 255 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UINTP, 256 EXUART_UINTP_RXD | EXUART_UINTP_ERROR | 257 EXUART_UINTP_TXD | EXUART_UINTP_MODEM); 258 259 sc->sc_ucon = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 260 EXUART_UCON); 261 CLR(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT_EMPTY_FIFO); 262 SET(sc->sc_ucon, EXUART_UCON_RX_INT_TYPE_LEVEL); 263 SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT); 264 bus_space_write_4(sc->sc_iot, sc->sc_ioh, EXUART_UCON, 265 sc->sc_ucon); 266 267 sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY, 268 exuart_intr, sc, sc->sc_dev.dv_xname); 269 } 270 271 timeout_set(&sc->sc_diag_tmo, exuart_diag, sc); 272 timeout_set(&sc->sc_dtr_tmo, exuart_raisedtr, sc); 273 sc->sc_si = softintr_establish(IPL_TTY, exuart_softint, sc); 274 275 if(sc->sc_si == NULL) 276 panic("%s: can't establish soft interrupt.", 277 sc->sc_dev.dv_xname); 278} 279 280void 281exuart_rx_intr(struct exuart_softc *sc) 282{ 283 bus_space_tag_t iot = sc->sc_iot; 284 bus_space_handle_t ioh = sc->sc_ioh; 285 u_int16_t *p; 286 u_int16_t c; 287 288 p = sc->sc_ibufp; 289 290 while (bus_space_read_4(iot, ioh, EXUART_UFSTAT) & 291 (sc->sc_rx_fifo_cnt_mask | sc->sc_rx_fifo_full)) { 292 c = bus_space_read_4(iot, ioh, EXUART_URXH); 293 if (p >= sc->sc_ibufend) { 294 sc->sc_floods++; 295 if (sc->sc_errors++ == 0) 296 timeout_add_sec(&sc->sc_diag_tmo, 60); 297 } else { 298 *p++ = c; 299#if 0 300 if (p == sc->sc_ibufhigh && 301 ISSET(tp->t_cflag, CRTSCTS)) { 302 /* XXX */ 303 } 304#endif 305 } 306 } 307 308 sc->sc_ibufp = p; 309 310 softintr_schedule(sc->sc_si); 311} 312 313void 314exuart_tx_intr(struct exuart_softc *sc) 315{ 316 struct tty *tp = sc->sc_tty; 317 318 if (ISSET(tp->t_state, TS_BUSY)) { 319 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 320 if (sc->sc_halt > 0) 321 wakeup(&tp->t_outq); 322 (*linesw[tp->t_line].l_start)(tp); 323 } 324} 325 326int 327exuart_intr(void *arg) 328{ 329 struct exuart_softc *sc = arg; 330 bus_space_tag_t iot = sc->sc_iot; 331 bus_space_handle_t ioh = sc->sc_ioh; 332 u_int32_t uintp; 333 334 uintp = bus_space_read_4(iot, ioh, EXUART_UINTP); 335 if (uintp == 0) 336 return (0); 337 338 if (sc->sc_tty == NULL) 339 return (0); 340 341 if (ISSET(uintp, EXUART_UINTP_RXD)) { 342 exuart_rx_intr(sc); 343 bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_RXD); 344 } 345 346 if (ISSET(uintp, EXUART_UINTP_TXD)) { 347 exuart_tx_intr(sc); 348 bus_space_write_4(iot, ioh, EXUART_UINTP, EXUART_UINTP_TXD); 349 } 350 351#if 0 352 if(!ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) 353 return 0; 354 355 p = sc->sc_ibufp; 356 357 while(ISSET(bus_space_read_2(iot, ioh, EXUART_USR2), EXUART_SR2_RDR)) { 358 c = bus_space_read_4(iot, ioh, EXUART_URXH); 359 if (p >= sc->sc_ibufend) { 360 sc->sc_floods++; 361 if (sc->sc_errors++ == 0) 362 timeout_add_sec(&sc->sc_diag_tmo, 60); 363 } else { 364 *p++ = c; 365 if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) 366 /* XXX */ 367 //CLR(sc->sc_ucr3, EXUART_CR3_DSR); 368 //bus_space_write_2(iot, ioh, EXUART_UCR3, 369 // sc->sc_ucr3); 370 371 } 372 /* XXX - msr stuff ? */ 373 } 374 sc->sc_ibufp = p; 375 376 softintr_schedule(sc->sc_si); 377#endif 378 379 return 1; 380} 381 382int 383exuart_s5l_intr(void *arg) 384{ 385 struct exuart_softc *sc = arg; 386 bus_space_tag_t iot = sc->sc_iot; 387 bus_space_handle_t ioh = sc->sc_ioh; 388 u_int32_t utrstat; 389 390 utrstat = bus_space_read_4(iot, ioh, EXUART_UTRSTAT); 391 392 if (sc->sc_tty == NULL) 393 return (0); 394 395 if (utrstat & (EXUART_S5L_UTRSTAT_RXTHRESH | 396 EXUART_S5L_UTRSTAT_RX_TIMEOUT)) 397 exuart_rx_intr(sc); 398 399 if (utrstat & EXUART_S5L_UTRSTAT_TXTHRESH) 400 exuart_tx_intr(sc); 401 402 bus_space_write_4(iot, ioh, EXUART_UTRSTAT, utrstat); 403 404 return 1; 405} 406 407int 408exuart_param(struct tty *tp, struct termios *t) 409{ 410 struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 411 bus_space_tag_t iot = sc->sc_iot; 412 bus_space_handle_t ioh = sc->sc_ioh; 413 int ospeed = t->c_ospeed; 414 int error; 415 tcflag_t oldcflag; 416 417 418 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 419 return EINVAL; 420 421 switch (ISSET(t->c_cflag, CSIZE)) { 422 case CS5: 423 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK); 424 SET(sc->sc_ulcon, EXUART_ULCON_WORD_FIVE); 425 break; 426 case CS6: 427 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK); 428 SET(sc->sc_ulcon, EXUART_ULCON_WORD_SIX); 429 break; 430 case CS7: 431 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK); 432 SET(sc->sc_ulcon, EXUART_ULCON_WORD_SEVEN); 433 break; 434 case CS8: 435 CLR(sc->sc_ulcon, EXUART_ULCON_WORD_MASK); 436 SET(sc->sc_ulcon, EXUART_ULCON_WORD_EIGHT); 437 break; 438 } 439 440 CLR(sc->sc_ulcon, EXUART_ULCON_PARITY_MASK); 441 if (ISSET(t->c_cflag, PARENB)) { 442 if (ISSET(t->c_cflag, PARODD)) 443 SET(sc->sc_ulcon, EXUART_ULCON_PARITY_ODD); 444 else 445 SET(sc->sc_ulcon, EXUART_ULCON_PARITY_EVEN); 446 } 447 448 if (ISSET(t->c_cflag, CSTOPB)) 449 SET(sc->sc_ulcon, EXUART_ULCON_STOP_TWO); 450 else 451 CLR(sc->sc_ulcon, EXUART_ULCON_STOP_ONE); 452 453 bus_space_write_4(iot, ioh, EXUART_ULCON, sc->sc_ulcon); 454 455 if (ospeed == 0) { 456 /* lower dtr */ 457 } 458 459 if (ospeed != 0) { 460 while (ISSET(tp->t_state, TS_BUSY)) { 461 ++sc->sc_halt; 462 error = ttysleep(tp, &tp->t_outq, 463 TTOPRI | PCATCH, "exuartprm"); 464 --sc->sc_halt; 465 if (error) { 466 exuart_start(tp); 467 return (error); 468 } 469 } 470 /* set speed */ 471 } 472 473 /* setup fifo */ 474 475 /* When not using CRTSCTS, RTS follows DTR. */ 476 /* sc->sc_dtr = MCR_DTR; */ 477 478 479 /* and copy to tty */ 480 tp->t_ispeed = t->c_ispeed; 481 tp->t_ospeed = t->c_ospeed; 482 oldcflag = tp->t_cflag; 483 tp->t_cflag = t->c_cflag; 484 485 /* 486 * If DCD is off and MDMBUF is changed, ask the tty layer if we should 487 * stop the device. 488 */ 489 /* XXX */ 490 491 exuart_start(tp); 492 493 return 0; 494} 495 496void 497exuart_start(struct tty *tp) 498{ 499 struct exuart_softc *sc = exuart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 500 bus_space_tag_t iot = sc->sc_iot; 501 bus_space_handle_t ioh = sc->sc_ioh; 502 int s; 503 504 s = spltty(); 505 if (ISSET(tp->t_state, TS_BUSY)) 506 goto out; 507 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0) 508 goto stopped; 509#ifdef DAMNFUCKSHIT 510 /* clear to send (IE the RTS pin on this shit) is not directly \ 511 * readable - skip check for now 512 */ 513 if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, EXUART_CTS)) 514 goto stopped; 515#endif 516 ttwakeupwr(tp); 517 if (tp->t_outq.c_cc == 0) 518 goto stopped; 519 SET(tp->t_state, TS_BUSY); 520 521 { 522 u_char buffer[16]; 523 int i, n; 524 525 n = q_to_b(&tp->t_outq, buffer, sizeof buffer); 526 for (i = 0; i < n; i++) 527 bus_space_write_4(iot, ioh, EXUART_UTXH, buffer[i]); 528 bzero(buffer, n); 529 } 530 531 if (sc->sc_type == EXUART_TYPE_S5L) { 532 if (!ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) { 533 SET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH); 534 bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon); 535 } 536 } else { 537 if (ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) { 538 CLR(sc->sc_uintm, EXUART_UINTM_TXD); 539 bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm); 540 } 541 } 542 543out: 544 splx(s); 545 return; 546stopped: 547 if (sc->sc_type == EXUART_TYPE_S5L) { 548 if (ISSET(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH)) { 549 CLR(sc->sc_ucon, EXUART_S5L_UCON_TXTHRESH); 550 bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon); 551 } 552 } else { 553 if (!ISSET(sc->sc_uintm, EXUART_UINTM_TXD)) { 554 SET(sc->sc_uintm, EXUART_UINTM_TXD); 555 bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm); 556 } 557 } 558 splx(s); 559} 560 561void 562exuart_diag(void *arg) 563{ 564 struct exuart_softc *sc = arg; 565 int overflows, floods; 566 int s; 567 568 s = spltty(); 569 sc->sc_errors = 0; 570 overflows = sc->sc_overflows; 571 sc->sc_overflows = 0; 572 floods = sc->sc_floods; 573 sc->sc_floods = 0; 574 splx(s); 575 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", 576 sc->sc_dev.dv_xname, 577 overflows, overflows == 1 ? "" : "s", 578 floods, floods == 1 ? "" : "s"); 579} 580 581void 582exuart_raisedtr(void *arg) 583{ 584 //struct exuart_softc *sc = arg; 585 586 //SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */ 587 //bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, sc->sc_ucr3); 588} 589 590void 591exuart_softint(void *arg) 592{ 593 struct exuart_softc *sc = arg; 594 struct tty *tp; 595 u_int16_t *ibufp; 596 u_int16_t *ibufend; 597 int c; 598 int err; 599 int s; 600 601 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 602 return; 603 604 tp = sc->sc_tty; 605 606 s = spltty(); 607 608 ibufp = sc->sc_ibuf; 609 ibufend = sc->sc_ibufp; 610 611 if (ibufp == ibufend) { 612 splx(s); 613 return; 614 } 615 616 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 617 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 618 sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER; 619 sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE; 620 621 if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 622 splx(s); 623 return; 624 } 625 626#if 0 627 if (ISSET(tp->t_cflag, CRTSCTS) && 628 !ISSET(sc->sc_ucr3, EXUART_CR3_DSR)) { 629 /* XXX */ 630 SET(sc->sc_ucr3, EXUART_CR3_DSR); 631 bus_space_write_2(sc->sc_iot, sc->sc_ioh, EXUART_UCR3, 632 sc->sc_ucr3); 633 } 634#endif 635 636 splx(s); 637 638 while (ibufp < ibufend) { 639 c = *ibufp++; 640#if 0 641 if (ISSET(c, EXUART_UERSTAT_OVERRUN)) { 642 sc->sc_overflows++; 643 if (sc->sc_errors++ == 0) 644 timeout_add_sec(&sc->sc_diag_tmo, 60); 645 } 646#endif 647 err = 0; 648#if 0 649 if (ISSET(c, EXUART_UERSTAT_PARITY)) 650 err |= TTY_PE; 651 if (ISSET(c, EXUART_UERSTAT_FRAME)) 652 err |= TTY_FE; 653#endif 654 c = (c & 0xff) | err; 655 (*linesw[tp->t_line].l_rint)(c, tp); 656 } 657} 658 659int 660exuartopen(dev_t dev, int flag, int mode, struct proc *p) 661{ 662 int unit = DEVUNIT(dev); 663 struct exuart_softc *sc; 664 bus_space_tag_t iot; 665 bus_space_handle_t ioh; 666 struct tty *tp; 667 int s; 668 int error = 0; 669 670 if (unit >= exuart_cd.cd_ndevs) 671 return ENXIO; 672 sc = exuart_cd.cd_devs[unit]; 673 if (sc == NULL) 674 return ENXIO; 675 676 s = spltty(); 677 if (sc->sc_tty == NULL) 678 tp = sc->sc_tty = ttymalloc(0); 679 else 680 tp = sc->sc_tty; 681 splx(s); 682 683 tp->t_oproc = exuart_start; 684 tp->t_param = exuart_param; 685 tp->t_dev = dev; 686 if (!ISSET(tp->t_state, TS_ISOPEN)) { 687 SET(tp->t_state, TS_WOPEN); 688 ttychars(tp); 689 tp->t_iflag = TTYDEF_IFLAG; 690 tp->t_oflag = TTYDEF_OFLAG; 691 692 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 693 tp->t_cflag = exuartconscflag; 694 else 695 tp->t_cflag = TTYDEF_CFLAG; 696 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) 697 SET(tp->t_cflag, CLOCAL); 698 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) 699 SET(tp->t_cflag, CRTSCTS); 700 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) 701 SET(tp->t_cflag, MDMBUF); 702 tp->t_lflag = TTYDEF_LFLAG; 703 tp->t_ispeed = tp->t_ospeed = exuartdefaultrate; 704 705 s = spltty(); 706 707 sc->sc_initialize = 1; 708 exuart_param(tp, &tp->t_termios); 709 ttsetwater(tp); 710 711 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 712 sc->sc_ibufhigh = sc->sc_ibuf + EXUART_IHIGHWATER; 713 sc->sc_ibufend = sc->sc_ibuf + EXUART_IBUFSIZE; 714 715 iot = sc->sc_iot; 716 ioh = sc->sc_ioh; 717 718 sc->sc_ulcon = bus_space_read_4(iot, ioh, EXUART_ULCON); 719 sc->sc_ucon = bus_space_read_4(iot, ioh, EXUART_UCON); 720 sc->sc_ufcon = bus_space_read_4(iot, ioh, EXUART_UFCON); 721 sc->sc_umcon = bus_space_read_4(iot, ioh, EXUART_UMCON); 722 723 if (sc->sc_type == EXUART_TYPE_S5L) { 724 SET(sc->sc_ucon, EXUART_UCON_RX_TIMEOUT); 725 SET(sc->sc_ucon, EXUART_S5L_UCON_RXTHRESH); 726 SET(sc->sc_ucon, EXUART_S5L_UCON_RX_TIMEOUT); 727 bus_space_write_4(iot, ioh, EXUART_UCON, sc->sc_ucon); 728 } else { 729 sc->sc_uintm = bus_space_read_4(iot, ioh, EXUART_UINTM); 730 CLR(sc->sc_uintm, EXUART_UINTM_RXD); 731 bus_space_write_4(iot, ioh, EXUART_UINTM, sc->sc_uintm); 732 } 733 734#if 0 735 /* interrupt after one char on tx/rx */ 736 /* reference frequency divider: 1 */ 737 bus_space_write_2(iot, ioh, EXUART_UFCR, 738 1 << EXUART_FCR_TXTL_SH | 739 5 << EXUART_FCR_RFDIV_SH | 740 1 << EXUART_FCR_RXTL_SH); 741 742 bus_space_write_2(iot, ioh, EXUART_UBIR, 743 (exuartdefaultrate / 100) - 1); 744 745 /* formula: clk / (rfdiv * 1600) */ 746 bus_space_write_2(iot, ioh, EXUART_UBMR, 747 (exccm_get_uartclk() * 1000) / 1600); 748 749 SET(sc->sc_ucr1, EXUART_CR1_EN|EXUART_CR1_RRDYEN); 750 SET(sc->sc_ucr2, EXUART_CR2_TXEN|EXUART_CR2_RXEN); 751 bus_space_write_2(iot, ioh, EXUART_UCR1, sc->sc_ucr1); 752 bus_space_write_2(iot, ioh, EXUART_UCR2, sc->sc_ucr2); 753 754 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */ 755 SET(sc->sc_ucr3, EXUART_CR3_DSR); /* XXX */ 756 bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3); 757#endif 758 759 SET(tp->t_state, TS_CARR_ON); /* XXX */ 760 761 762 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) 763 return EBUSY; 764 else 765 s = spltty(); 766 767 if (DEVCUA(dev)) { 768 if (ISSET(tp->t_state, TS_ISOPEN)) { 769 splx(s); 770 return EBUSY; 771 } 772 sc->sc_cua = 1; 773 } else { 774 /* tty (not cua) device; wait for carrier if necessary */ 775 if (ISSET(flag, O_NONBLOCK)) { 776 if (sc->sc_cua) { 777 /* Opening TTY non-blocking... but the CUA is busy */ 778 splx(s); 779 return EBUSY; 780 } 781 } else { 782 while (sc->sc_cua || 783 (!ISSET(tp->t_cflag, CLOCAL) && 784 !ISSET(tp->t_state, TS_CARR_ON))) { 785 SET(tp->t_state, TS_WOPEN); 786 error = ttysleep(tp, &tp->t_rawq, 787 TTIPRI | PCATCH, ttopen); 788 /* 789 * If TS_WOPEN has been reset, that means the 790 * cua device has been closed. We don't want 791 * to fail in that case, 792 * so just go around again. 793 */ 794 if (error && ISSET(tp->t_state, TS_WOPEN)) { 795 CLR(tp->t_state, TS_WOPEN); 796 splx(s); 797 return error; 798 } 799 } 800 } 801 } 802 splx(s); 803 804 return (*linesw[tp->t_line].l_open)(dev,tp,p); 805} 806 807int 808exuartclose(dev_t dev, int flag, int mode, struct proc *p) 809{ 810 int unit = DEVUNIT(dev); 811 struct exuart_softc *sc = exuart_cd.cd_devs[unit]; 812 //bus_space_tag_t iot = sc->sc_iot; 813 //bus_space_handle_t ioh = sc->sc_ioh; 814 struct tty *tp = sc->sc_tty; 815 int s; 816 817 /* XXX This is for cons.c. */ 818 if (!ISSET(tp->t_state, TS_ISOPEN)) 819 return 0; 820 821 (*linesw[tp->t_line].l_close)(tp, flag, p); 822 s = spltty(); 823 if (ISSET(tp->t_state, TS_WOPEN)) { 824 /* tty device is waiting for carrier; drop dtr then re-raise */ 825 //CLR(sc->sc_ucr3, EXUART_CR3_DSR); 826 //bus_space_write_2(iot, ioh, EXUART_UCR3, sc->sc_ucr3); 827 timeout_add_sec(&sc->sc_dtr_tmo, 2); 828 } 829 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 830 sc->sc_cua = 0; 831 splx(s); 832 ttyclose(tp); 833 834 return 0; 835} 836 837int 838exuartread(dev_t dev, struct uio *uio, int flag) 839{ 840 struct tty *tty; 841 842 tty = exuarttty(dev); 843 if (tty == NULL) 844 return ENODEV; 845 846 return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 847} 848 849int 850exuartwrite(dev_t dev, struct uio *uio, int flag) 851{ 852 struct tty *tty; 853 854 tty = exuarttty(dev); 855 if (tty == NULL) 856 return ENODEV; 857 858 return((*linesw[tty->t_line].l_write)(tty, uio, flag)); 859} 860 861int 862exuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 863{ 864 struct exuart_softc *sc; 865 struct tty *tp; 866 int error; 867 868 sc = exuart_sc(dev); 869 if (sc == NULL) 870 return (ENODEV); 871 872 tp = sc->sc_tty; 873 if (tp == NULL) 874 return (ENXIO); 875 876 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 877 if (error >= 0) 878 return (error); 879 880 error = ttioctl(tp, cmd, data, flag, p); 881 if (error >= 0) 882 return (error); 883 884 switch(cmd) { 885 case TIOCSBRK: 886 /* */ 887 break; 888 889 case TIOCCBRK: 890 /* */ 891 break; 892 893 case TIOCSDTR: 894#if 0 895 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); 896#endif 897 break; 898 899 case TIOCCDTR: 900#if 0 901 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); 902#endif 903 break; 904 905 case TIOCMSET: 906#if 0 907 (void) clmctl(dev, *(int *) data, DMSET); 908#endif 909 break; 910 911 case TIOCMBIS: 912#if 0 913 (void) clmctl(dev, *(int *) data, DMBIS); 914#endif 915 break; 916 917 case TIOCMBIC: 918#if 0 919 (void) clmctl(dev, *(int *) data, DMBIC); 920#endif 921 break; 922 923 case TIOCMGET: 924#if 0 925 *(int *)data = clmctl(dev, 0, DMGET); 926#endif 927 break; 928 929 case TIOCGFLAGS: 930#if 0 931 *(int *)data = cl->cl_swflags; 932#endif 933 break; 934 935 case TIOCSFLAGS: 936 error = suser(p); 937 if (error != 0) 938 return(EPERM); 939 940#if 0 941 cl->cl_swflags = *(int *)data; 942 cl->cl_swflags &= /* only allow valid flags */ 943 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 944#endif 945 break; 946 default: 947 return (ENOTTY); 948 } 949 950 return 0; 951} 952 953int 954exuartstop(struct tty *tp, int flag) 955{ 956 return 0; 957} 958 959struct tty * 960exuarttty(dev_t dev) 961{ 962 int unit; 963 struct exuart_softc *sc; 964 unit = DEVUNIT(dev); 965 if (unit >= exuart_cd.cd_ndevs) 966 return NULL; 967 sc = (struct exuart_softc *)exuart_cd.cd_devs[unit]; 968 if (sc == NULL) 969 return NULL; 970 return sc->sc_tty; 971} 972 973struct exuart_softc * 974exuart_sc(dev_t dev) 975{ 976 int unit; 977 struct exuart_softc *sc; 978 unit = DEVUNIT(dev); 979 if (unit >= exuart_cd.cd_ndevs) 980 return NULL; 981 sc = (struct exuart_softc *)exuart_cd.cd_devs[unit]; 982 return sc; 983} 984 985 986/* serial console */ 987void 988exuartcnprobe(struct consdev *cp) 989{ 990} 991 992void 993exuartcninit(struct consdev *cp) 994{ 995} 996 997int 998exuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 999{ 1000 static struct consdev exuartcons = { 1001 NULL, NULL, exuartcngetc, exuartcnputc, exuartcnpollc, NULL, 1002 NODEV, CN_MIDPRI 1003 }; 1004 int maj; 1005 1006 if (bus_space_map(iot, iobase, 0x100, 0, &exuartconsioh)) 1007 return ENOMEM; 1008 1009 /* Look for major of com(4) to replace. */ 1010 for (maj = 0; maj < nchrdev; maj++) 1011 if (cdevsw[maj].d_open == comopen) 1012 break; 1013 if (maj == nchrdev) 1014 return ENXIO; 1015 1016 cn_tab = &exuartcons; 1017 cn_tab->cn_dev = makedev(maj, 0); 1018 cdevsw[maj] = exuartdev; /* KLUDGE */ 1019 1020 exuartconsiot = iot; 1021 exuartconsaddr = iobase; 1022 exuartconscflag = cflag; 1023 1024 return 0; 1025} 1026 1027int 1028exuartcngetc(dev_t dev) 1029{ 1030 int c; 1031 int s; 1032 s = splhigh(); 1033 while((bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UTRSTAT) & 1034 EXUART_UTRSTAT_RXBREADY) == 0 && 1035 (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) & 1036 (exuart_rx_fifo_cnt_mask | exuart_rx_fifo_full)) == 0) 1037 ; 1038 c = bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_URXH); 1039 splx(s); 1040 return c; 1041} 1042 1043void 1044exuartcnputc(dev_t dev, int c) 1045{ 1046 int s; 1047 s = splhigh(); 1048 while (bus_space_read_4(exuartconsiot, exuartconsioh, EXUART_UFSTAT) & 1049 exuart_tx_fifo_full) 1050 ; 1051 bus_space_write_4(exuartconsiot, exuartconsioh, EXUART_UTXH, c); 1052 splx(s); 1053} 1054 1055void 1056exuartcnpollc(dev_t dev, int on) 1057{ 1058} 1059