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