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