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