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