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