1 /* $OpenBSD: imxuart.c,v 1.11 2021/09/01 09:29:31 jan Exp $ */ 2 /* 3 * Copyright (c) 2005 Dale Rahn <drahn@motorola.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/ioctl.h> 20 #include <sys/proc.h> 21 #include <sys/tty.h> 22 #include <sys/uio.h> 23 #include <sys/systm.h> 24 #include <sys/time.h> 25 #include <sys/device.h> 26 #include <sys/syslog.h> 27 #include <sys/conf.h> 28 #include <sys/fcntl.h> 29 #include <sys/select.h> 30 #include <sys/kernel.h> 31 32 #include <machine/bus.h> 33 #include <machine/fdt.h> 34 35 #include <dev/cons.h> 36 37 #ifdef DDB 38 #include <ddb/db_var.h> 39 #endif 40 41 #include <dev/fdt/imxuartreg.h> 42 43 #include <dev/ofw/openfirm.h> 44 #include <dev/ofw/ofw_clock.h> 45 #include <dev/ofw/ofw_pinctrl.h> 46 #include <dev/ofw/fdt.h> 47 48 #define DEVUNIT(x) (minor(x) & 0x7f) 49 #define DEVCUA(x) (minor(x) & 0x80) 50 51 struct imxuart_softc { 52 struct device sc_dev; 53 bus_space_tag_t sc_iot; 54 bus_space_handle_t sc_ioh; 55 int sc_node; 56 struct soft_intrhand *sc_si; 57 void *sc_irq; 58 struct tty *sc_tty; 59 struct timeout sc_diag_tmo; 60 struct timeout sc_dtr_tmo; 61 int sc_overflows; 62 int sc_floods; 63 int sc_errors; 64 int sc_halt; 65 u_int16_t sc_ucr1; 66 u_int16_t sc_ucr2; 67 u_int16_t sc_ucr3; 68 u_int16_t sc_ucr4; 69 u_int8_t sc_hwflags; 70 #define COM_HW_NOIEN 0x01 71 #define COM_HW_FIFO 0x02 72 #define COM_HW_SIR 0x20 73 #define COM_HW_CONSOLE 0x40 74 u_int8_t sc_swflags; 75 #define COM_SW_SOFTCAR 0x01 76 #define COM_SW_CLOCAL 0x02 77 #define COM_SW_CRTSCTS 0x04 78 #define COM_SW_MDMBUF 0x08 79 #define COM_SW_PPS 0x10 80 81 u_int8_t sc_initialize; 82 u_int8_t sc_cua; 83 u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend; 84 #define IMXUART_IBUFSIZE 128 85 #define IMXUART_IHIGHWATER 100 86 u_int16_t sc_ibufs[2][IMXUART_IBUFSIZE]; 87 }; 88 89 int imxuart_match(struct device *, void *, void *); 90 void imxuart_attach(struct device *, struct device *, void *); 91 92 void imxuartcnprobe(struct consdev *cp); 93 void imxuartcninit(struct consdev *cp); 94 int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, 95 tcflag_t cflag); 96 int imxuartcngetc(dev_t dev); 97 void imxuartcnputc(dev_t dev, int c); 98 void imxuartcnpollc(dev_t dev, int on); 99 int imxuart_param(struct tty *tp, struct termios *t); 100 void imxuart_start(struct tty *); 101 void imxuart_diag(void *arg); 102 void imxuart_raisedtr(void *arg); 103 void imxuart_softint(void *arg); 104 struct imxuart_softc *imxuart_sc(dev_t dev); 105 106 int imxuart_intr(void *); 107 108 /* XXX - we imitate 'com' serial ports and take over their entry points */ 109 /* XXX: These belong elsewhere */ 110 cdev_decl(com); 111 cdev_decl(imxuart); 112 113 struct cfdriver imxuart_cd = { 114 NULL, "imxuart", DV_TTY 115 }; 116 117 struct cfattach imxuart_ca = { 118 sizeof(struct imxuart_softc), imxuart_match, imxuart_attach 119 }; 120 121 bus_space_tag_t imxuartconsiot; 122 bus_space_handle_t imxuartconsioh; 123 bus_addr_t imxuartconsaddr; 124 tcflag_t imxuartconscflag = TTYDEF_CFLAG; 125 int imxuartdefaultrate = B115200; 126 127 struct cdevsw imxuartdev = 128 cdev_tty_init(3/*XXX NIMXUART */ ,imxuart); /* 12: serial port */ 129 130 void 131 imxuart_init_cons(void) 132 { 133 struct fdt_reg reg; 134 void *node; 135 136 if ((node = fdt_find_cons("fsl,imx21-uart")) == NULL && 137 (node = fdt_find_cons("fsl,imx6q-uart")) == NULL) 138 return; 139 140 if (fdt_get_reg(node, 0, ®)) 141 return; 142 143 imxuartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG); 144 } 145 146 int 147 imxuart_match(struct device *parent, void *match, void *aux) 148 { 149 struct fdt_attach_args *faa = aux; 150 151 return (OF_is_compatible(faa->fa_node, "fsl,imx21-uart") || 152 OF_is_compatible(faa->fa_node, "fsl,imx6q-uart")); 153 } 154 155 void 156 imxuart_attach(struct device *parent, struct device *self, void *aux) 157 { 158 struct imxuart_softc *sc = (struct imxuart_softc *) self; 159 struct fdt_attach_args *faa = aux; 160 int maj; 161 162 if (faa->fa_nreg < 1) 163 return; 164 165 pinctrl_byname(faa->fa_node, "default"); 166 167 sc->sc_irq = fdt_intr_establish(faa->fa_node, IPL_TTY, 168 imxuart_intr, sc, sc->sc_dev.dv_xname); 169 170 sc->sc_node = faa->fa_node; 171 sc->sc_iot = faa->fa_iot; 172 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 173 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 174 panic("imxuartattach: bus_space_map failed!"); 175 176 if (faa->fa_reg[0].addr == imxuartconsaddr) { 177 /* Locate the major number. */ 178 for (maj = 0; maj < nchrdev; maj++) 179 if (cdevsw[maj].d_open == imxuartopen) 180 break; 181 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 182 183 SET(sc->sc_hwflags, COM_HW_CONSOLE); 184 printf(": console"); 185 } 186 187 timeout_set(&sc->sc_diag_tmo, imxuart_diag, sc); 188 timeout_set(&sc->sc_dtr_tmo, imxuart_raisedtr, sc); 189 sc->sc_si = softintr_establish(IPL_TTY, imxuart_softint, sc); 190 191 if(sc->sc_si == NULL) 192 panic("%s: can't establish soft interrupt.", 193 sc->sc_dev.dv_xname); 194 195 printf("\n"); 196 } 197 198 int 199 imxuart_intr(void *arg) 200 { 201 struct imxuart_softc *sc = arg; 202 bus_space_tag_t iot = sc->sc_iot; 203 bus_space_handle_t ioh = sc->sc_ioh; 204 struct tty *tp = sc->sc_tty; 205 u_int16_t sr1; 206 u_int16_t *p; 207 u_int16_t c; 208 209 sr1 = bus_space_read_2(iot, ioh, IMXUART_USR1); 210 if (ISSET(sr1, IMXUART_SR1_TRDY) && ISSET(tp->t_state, TS_BUSY)) { 211 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 212 if (sc->sc_halt > 0) 213 wakeup(&tp->t_outq); 214 (*linesw[tp->t_line].l_start)(tp); 215 } 216 217 if (sc->sc_tty == NULL) 218 return(0); 219 220 if(!ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR)) 221 return 0; 222 223 p = sc->sc_ibufp; 224 225 while(ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR)) { 226 c = bus_space_read_2(iot, ioh, IMXUART_URXD); 227 if (ISSET(c, IMXUART_RX_BRK)) { 228 #ifdef DDB 229 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 230 if (db_console) 231 db_enter(); 232 continue; 233 } 234 #endif 235 c &= ~0xff; 236 } 237 if (p >= sc->sc_ibufend) { 238 sc->sc_floods++; 239 if (sc->sc_errors++ == 0) 240 timeout_add_sec(&sc->sc_diag_tmo, 60); 241 } else { 242 *p++ = c; 243 if (p == sc->sc_ibufhigh && 244 ISSET(tp->t_cflag, CRTSCTS)) { 245 /* XXX */ 246 CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 247 bus_space_write_2(iot, ioh, IMXUART_UCR3, 248 sc->sc_ucr3); 249 } 250 251 } 252 /* XXX - msr stuff ? */ 253 } 254 sc->sc_ibufp = p; 255 256 softintr_schedule(sc->sc_si); 257 258 return 1; 259 } 260 261 int 262 imxuart_param(struct tty *tp, struct termios *t) 263 { 264 struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 265 bus_space_tag_t iot = sc->sc_iot; 266 bus_space_handle_t ioh = sc->sc_ioh; 267 int ospeed = t->c_ospeed; 268 int error; 269 tcflag_t oldcflag; 270 271 272 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 273 return EINVAL; 274 275 switch (ISSET(t->c_cflag, CSIZE)) { 276 case CS5: 277 return EINVAL; 278 case CS6: 279 return EINVAL; 280 case CS7: 281 CLR(sc->sc_ucr2, IMXUART_CR2_WS); 282 break; 283 case CS8: 284 SET(sc->sc_ucr2, IMXUART_CR2_WS); 285 break; 286 } 287 // bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 288 289 if (ISSET(t->c_cflag, PARENB)) { 290 SET(sc->sc_ucr2, IMXUART_CR2_PREN); 291 bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 292 } 293 /* STOPB - XXX */ 294 if (ospeed == 0) { 295 /* lower dtr */ 296 } 297 298 if (ospeed != 0) { 299 while (ISSET(tp->t_state, TS_BUSY)) { 300 ++sc->sc_halt; 301 error = ttysleep(tp, &tp->t_outq, 302 TTOPRI | PCATCH, "imxuartprm"); 303 --sc->sc_halt; 304 if (error) { 305 imxuart_start(tp); 306 return (error); 307 } 308 } 309 /* set speed */ 310 } 311 312 /* setup fifo */ 313 314 /* When not using CRTSCTS, RTS follows DTR. */ 315 /* sc->sc_dtr = MCR_DTR; */ 316 317 318 /* and copy to tty */ 319 tp->t_ispeed = t->c_ispeed; 320 tp->t_ospeed = t->c_ospeed; 321 oldcflag = tp->t_cflag; 322 tp->t_cflag = t->c_cflag; 323 324 /* 325 * If DCD is off and MDMBUF is changed, ask the tty layer if we should 326 * stop the device. 327 */ 328 /* XXX */ 329 330 imxuart_start(tp); 331 332 return 0; 333 } 334 335 void 336 imxuart_start(struct tty *tp) 337 { 338 struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 339 bus_space_tag_t iot = sc->sc_iot; 340 bus_space_handle_t ioh = sc->sc_ioh; 341 342 int s; 343 s = spltty(); 344 if (ISSET(tp->t_state, TS_BUSY)) { 345 splx(s); 346 return; 347 } 348 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP)) 349 goto stopped; 350 #ifdef DAMNFUCKSHIT 351 /* clear to send (IE the RTS pin on this shit) is not directly \ 352 * readable - skip check for now 353 */ 354 if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, IMXUART_CTS)) 355 goto stopped; 356 #endif 357 if (tp->t_outq.c_cc <= tp->t_lowat) { 358 if (ISSET(tp->t_state, TS_ASLEEP)) { 359 CLR(tp->t_state, TS_ASLEEP); 360 wakeup(&tp->t_outq); 361 } 362 if (tp->t_outq.c_cc == 0) 363 goto stopped; 364 selwakeup(&tp->t_wsel); 365 } 366 SET(tp->t_state, TS_BUSY); 367 368 if (!ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) { 369 SET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN); 370 bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 371 } 372 373 { 374 u_char buf[32]; 375 int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/); 376 int i; 377 for (i = 0; i < n; i++) 378 bus_space_write_1(iot, ioh, IMXUART_UTXD, buf[i]); 379 } 380 splx(s); 381 return; 382 stopped: 383 if (ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) { 384 CLR(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN); 385 bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 386 } 387 splx(s); 388 } 389 390 void 391 imxuart_diag(void *arg) 392 { 393 struct imxuart_softc *sc = arg; 394 int overflows, floods; 395 int s; 396 397 s = spltty(); 398 sc->sc_errors = 0; 399 overflows = sc->sc_overflows; 400 sc->sc_overflows = 0; 401 floods = sc->sc_floods; 402 sc->sc_floods = 0; 403 splx(s); 404 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", 405 sc->sc_dev.dv_xname, 406 overflows, overflows == 1 ? "" : "s", 407 floods, floods == 1 ? "" : "s"); 408 } 409 410 void 411 imxuart_raisedtr(void *arg) 412 { 413 struct imxuart_softc *sc = arg; 414 415 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 416 bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3); 417 } 418 419 void 420 imxuart_softint(void *arg) 421 { 422 struct imxuart_softc *sc = arg; 423 struct tty *tp; 424 u_int16_t *ibufp; 425 u_int16_t *ibufend; 426 int c; 427 int err; 428 int s; 429 430 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 431 return; 432 433 tp = sc->sc_tty; 434 s = spltty(); 435 436 ibufp = sc->sc_ibuf; 437 ibufend = sc->sc_ibufp; 438 439 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 440 splx(s); 441 return; 442 } 443 444 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 445 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 446 sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER; 447 sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE; 448 449 if (ISSET(tp->t_cflag, CRTSCTS) && 450 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) { 451 /* XXX */ 452 SET(sc->sc_ucr3, IMXUART_CR3_DSR); 453 bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, 454 sc->sc_ucr3); 455 } 456 457 splx(s); 458 459 while (ibufp < ibufend) { 460 c = *ibufp++; 461 if (ISSET(c, IMXUART_RX_OVERRUN)) { 462 sc->sc_overflows++; 463 if (sc->sc_errors++ == 0) 464 timeout_add_sec(&sc->sc_diag_tmo, 60); 465 } 466 /* This is ugly, but fast. */ 467 468 err = 0; 469 if (ISSET(c, IMXUART_RX_PRERR)) 470 err |= TTY_PE; 471 if (ISSET(c, IMXUART_RX_FRMERR)) 472 err |= TTY_FE; 473 c = (c & 0xff) | err; 474 (*linesw[tp->t_line].l_rint)(c, tp); 475 } 476 } 477 478 int 479 imxuartopen(dev_t dev, int flag, int mode, struct proc *p) 480 { 481 int unit = DEVUNIT(dev); 482 struct imxuart_softc *sc; 483 bus_space_tag_t iot; 484 bus_space_handle_t ioh; 485 struct tty *tp; 486 int s; 487 int error = 0; 488 489 if (unit >= imxuart_cd.cd_ndevs) 490 return ENXIO; 491 sc = imxuart_cd.cd_devs[unit]; 492 if (sc == NULL) 493 return ENXIO; 494 495 s = spltty(); 496 if (sc->sc_tty == NULL) 497 tp = sc->sc_tty = ttymalloc(0); 498 else 499 tp = sc->sc_tty; 500 501 splx(s); 502 503 tp->t_oproc = imxuart_start; 504 tp->t_param = imxuart_param; 505 tp->t_dev = dev; 506 507 if (!ISSET(tp->t_state, TS_ISOPEN)) { 508 SET(tp->t_state, TS_WOPEN); 509 ttychars(tp); 510 tp->t_iflag = TTYDEF_IFLAG; 511 tp->t_oflag = TTYDEF_OFLAG; 512 513 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 514 tp->t_cflag = imxuartconscflag; 515 else 516 tp->t_cflag = TTYDEF_CFLAG; 517 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) 518 SET(tp->t_cflag, CLOCAL); 519 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) 520 SET(tp->t_cflag, CRTSCTS); 521 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) 522 SET(tp->t_cflag, MDMBUF); 523 tp->t_lflag = TTYDEF_LFLAG; 524 tp->t_ispeed = tp->t_ospeed = imxuartdefaultrate; 525 526 s = spltty(); 527 528 sc->sc_initialize = 1; 529 imxuart_param(tp, &tp->t_termios); 530 ttsetwater(tp); 531 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 532 sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER; 533 sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE; 534 535 iot = sc->sc_iot; 536 ioh = sc->sc_ioh; 537 538 sc->sc_ucr1 = bus_space_read_2(iot, ioh, IMXUART_UCR1); 539 sc->sc_ucr2 = bus_space_read_2(iot, ioh, IMXUART_UCR2); 540 sc->sc_ucr3 = bus_space_read_2(iot, ioh, IMXUART_UCR3); 541 sc->sc_ucr4 = bus_space_read_2(iot, ioh, IMXUART_UCR4); 542 543 /* interrupt after one char on tx/rx */ 544 /* reference frequency divider: 1 */ 545 bus_space_write_2(iot, ioh, IMXUART_UFCR, 546 1 << IMXUART_FCR_TXTL_SH | 547 5 << IMXUART_FCR_RFDIV_SH | 548 1 << IMXUART_FCR_RXTL_SH); 549 550 bus_space_write_2(iot, ioh, IMXUART_UBIR, 551 (imxuartdefaultrate / 100) - 1); 552 553 /* formula: clk / (rfdiv * 1600) */ 554 bus_space_write_2(iot, ioh, IMXUART_UBMR, 555 clock_get_frequency(sc->sc_node, "per") / 1600); 556 557 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN); 558 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN); 559 bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 560 bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 561 562 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */ 563 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 564 bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 565 566 SET(tp->t_state, TS_CARR_ON); /* XXX */ 567 568 569 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) 570 return EBUSY; 571 else 572 s = spltty(); 573 574 if (DEVCUA(dev)) { 575 if (ISSET(tp->t_state, TS_ISOPEN)) { 576 splx(s); 577 return EBUSY; 578 } 579 sc->sc_cua = 1; 580 } else { 581 /* tty (not cua) device; wait for carrier if necessary */ 582 if (ISSET(flag, O_NONBLOCK)) { 583 if (sc->sc_cua) { 584 /* Opening TTY non-blocking... but the CUA is busy */ 585 splx(s); 586 return EBUSY; 587 } 588 } else { 589 while (sc->sc_cua || 590 (!ISSET(tp->t_cflag, CLOCAL) && 591 !ISSET(tp->t_state, TS_CARR_ON))) { 592 SET(tp->t_state, TS_WOPEN); 593 error = ttysleep(tp, &tp->t_rawq, 594 TTIPRI | PCATCH, ttopen); 595 /* 596 * If TS_WOPEN has been reset, that means the 597 * cua device has been closed. We don't want 598 * to fail in that case, 599 * so just go around again. 600 */ 601 if (error && ISSET(tp->t_state, TS_WOPEN)) { 602 CLR(tp->t_state, TS_WOPEN); 603 splx(s); 604 return error; 605 } 606 } 607 } 608 } 609 splx(s); 610 return (*linesw[tp->t_line].l_open)(dev,tp,p); 611 } 612 613 int 614 imxuartclose(dev_t dev, int flag, int mode, struct proc *p) 615 { 616 int unit = DEVUNIT(dev); 617 struct imxuart_softc *sc = imxuart_cd.cd_devs[unit]; 618 bus_space_tag_t iot = sc->sc_iot; 619 bus_space_handle_t ioh = sc->sc_ioh; 620 struct tty *tp = sc->sc_tty; 621 int s; 622 623 /* XXX This is for cons.c. */ 624 if (!ISSET(tp->t_state, TS_ISOPEN)) 625 return 0; 626 627 (*linesw[tp->t_line].l_close)(tp, flag, p); 628 s = spltty(); 629 if (ISSET(tp->t_state, TS_WOPEN)) { 630 /* tty device is waiting for carrier; drop dtr then re-raise */ 631 CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 632 bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 633 timeout_add_sec(&sc->sc_dtr_tmo, 2); 634 } 635 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 636 637 sc->sc_cua = 0; 638 splx(s); 639 ttyclose(tp); 640 641 return 0; 642 } 643 644 int 645 imxuartread(dev_t dev, struct uio *uio, int flag) 646 { 647 struct tty *tty; 648 649 tty = imxuarttty(dev); 650 if (tty == NULL) 651 return ENODEV; 652 653 return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 654 } 655 656 int 657 imxuartwrite(dev_t dev, struct uio *uio, int flag) 658 { 659 struct tty *tty; 660 661 tty = imxuarttty(dev); 662 if (tty == NULL) 663 return ENODEV; 664 665 return((*linesw[tty->t_line].l_write)(tty, uio, flag)); 666 } 667 668 int 669 imxuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 670 { 671 struct imxuart_softc *sc; 672 struct tty *tp; 673 int error; 674 675 sc = imxuart_sc(dev); 676 if (sc == NULL) 677 return (ENODEV); 678 679 tp = sc->sc_tty; 680 if (tp == NULL) 681 return (ENXIO); 682 683 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 684 if (error >= 0) 685 return (error); 686 687 error = ttioctl(tp, cmd, data, flag, p); 688 if (error >= 0) 689 return (error); 690 691 switch(cmd) { 692 case TIOCSBRK: 693 /* */ 694 break; 695 696 case TIOCCBRK: 697 /* */ 698 break; 699 700 case TIOCSDTR: 701 #if 0 702 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); 703 #endif 704 break; 705 706 case TIOCCDTR: 707 #if 0 708 (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); 709 #endif 710 break; 711 712 case TIOCMSET: 713 #if 0 714 (void) clmctl(dev, *(int *) data, DMSET); 715 #endif 716 break; 717 718 case TIOCMBIS: 719 #if 0 720 (void) clmctl(dev, *(int *) data, DMBIS); 721 #endif 722 break; 723 724 case TIOCMBIC: 725 #if 0 726 (void) clmctl(dev, *(int *) data, DMBIC); 727 #endif 728 break; 729 730 case TIOCMGET: 731 #if 0 732 *(int *)data = clmctl(dev, 0, DMGET); 733 #endif 734 break; 735 736 case TIOCGFLAGS: 737 #if 0 738 *(int *)data = cl->cl_swflags; 739 #endif 740 break; 741 742 case TIOCSFLAGS: 743 error = suser(p); 744 if (error != 0) 745 return(EPERM); 746 747 #if 0 748 cl->cl_swflags = *(int *)data; 749 cl->cl_swflags &= /* only allow valid flags */ 750 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 751 #endif 752 break; 753 default: 754 return (ENOTTY); 755 } 756 757 return 0; 758 } 759 760 int 761 imxuartstop(struct tty *tp, int flag) 762 { 763 return 0; 764 } 765 766 struct tty * 767 imxuarttty(dev_t dev) 768 { 769 int unit; 770 struct imxuart_softc *sc; 771 unit = DEVUNIT(dev); 772 if (unit >= imxuart_cd.cd_ndevs) 773 return NULL; 774 sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit]; 775 if (sc == NULL) 776 return NULL; 777 return sc->sc_tty; 778 } 779 780 struct imxuart_softc * 781 imxuart_sc(dev_t dev) 782 { 783 int unit; 784 struct imxuart_softc *sc; 785 unit = DEVUNIT(dev); 786 if (unit >= imxuart_cd.cd_ndevs) 787 return NULL; 788 sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit]; 789 return sc; 790 } 791 792 793 /* serial console */ 794 void 795 imxuartcnprobe(struct consdev *cp) 796 { 797 } 798 799 void 800 imxuartcninit(struct consdev *cp) 801 { 802 } 803 804 int 805 imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 806 { 807 static struct consdev imxuartcons = { 808 NULL, NULL, imxuartcngetc, imxuartcnputc, imxuartcnpollc, NULL, 809 NODEV, CN_MIDPRI 810 }; 811 int maj; 812 813 if (bus_space_map(iot, iobase, IMXUART_SPACE, 0, &imxuartconsioh)) 814 return ENOMEM; 815 816 /* Look for major of com(4) to replace. */ 817 for (maj = 0; maj < nchrdev; maj++) 818 if (cdevsw[maj].d_open == comopen) 819 break; 820 if (maj == nchrdev) 821 return ENXIO; 822 823 cn_tab = &imxuartcons; 824 cn_tab->cn_dev = makedev(maj, 0); 825 cdevsw[maj] = imxuartdev; /* KLUDGE */ 826 827 imxuartconsiot = iot; 828 imxuartconsaddr = iobase; 829 imxuartconscflag = cflag; 830 831 // XXXX: Overwrites some sensitive bits, recheck later. 832 /* 833 bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR1, 834 IMXUART_CR1_EN); 835 bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR2, 836 IMXUART_CR2_TXEN|IMXUART_CR2_RXEN); 837 */ 838 839 return 0; 840 } 841 842 int 843 imxuartcngetc(dev_t dev) 844 { 845 int c; 846 int s; 847 s = splhigh(); 848 while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) & 849 IMXUART_SR2_RDR) == 0) 850 ; 851 c = bus_space_read_1(imxuartconsiot, imxuartconsioh, IMXUART_URXD); 852 splx(s); 853 return c; 854 } 855 856 void 857 imxuartcnputc(dev_t dev, int c) 858 { 859 int s; 860 s = splhigh(); 861 bus_space_write_1(imxuartconsiot, imxuartconsioh, IMXUART_UTXD, (uint8_t)c); 862 while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) & 863 IMXUART_SR2_TXDC) == 0) 864 ; 865 splx(s); 866 } 867 868 void 869 imxuartcnpollc(dev_t dev, int on) 870 { 871 } 872