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