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