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