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