1 /* $OpenBSD: pluart.c,v 1.5 2020/01/10 04:10:15 cheloha Exp $ */ 2 /* 3 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se> 4 * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/ioctl.h> 21 #include <sys/proc.h> 22 #include <sys/tty.h> 23 #include <sys/uio.h> 24 #include <sys/systm.h> 25 #include <sys/time.h> 26 #include <sys/device.h> 27 #include <sys/syslog.h> 28 #include <sys/conf.h> 29 #include <sys/fcntl.h> 30 #include <sys/select.h> 31 #include <sys/kernel.h> 32 33 #include <machine/bus.h> 34 35 #include <dev/ic/pluartvar.h> 36 #include <dev/cons.h> 37 38 #ifdef DDB 39 #include <ddb/db_var.h> 40 #endif 41 42 #define DEVUNIT(x) (minor(x) & 0x7f) 43 #define DEVCUA(x) (minor(x) & 0x80) 44 45 #define UART_DR 0x00 /* Data register */ 46 #define UART_DR_DATA(x) ((x) & 0xf) 47 #define UART_DR_FE (1 << 8) /* Framing error */ 48 #define UART_DR_PE (1 << 9) /* Parity error */ 49 #define UART_DR_BE (1 << 10) /* Break error */ 50 #define UART_DR_OE (1 << 11) /* Overrun error */ 51 #define UART_RSR 0x04 /* Receive status register */ 52 #define UART_RSR_FE (1 << 0) /* Framing error */ 53 #define UART_RSR_PE (1 << 1) /* Parity error */ 54 #define UART_RSR_BE (1 << 2) /* Break error */ 55 #define UART_RSR_OE (1 << 3) /* Overrun error */ 56 #define UART_ECR 0x04 /* Error clear register */ 57 #define UART_ECR_FE (1 << 0) /* Framing error */ 58 #define UART_ECR_PE (1 << 1) /* Parity error */ 59 #define UART_ECR_BE (1 << 2) /* Break error */ 60 #define UART_ECR_OE (1 << 3) /* Overrun error */ 61 #define UART_FR 0x18 /* Flag register */ 62 #define UART_FR_CTS (1 << 0) /* Clear to send */ 63 #define UART_FR_DSR (1 << 1) /* Data set ready */ 64 #define UART_FR_DCD (1 << 2) /* Data carrier detect */ 65 #define UART_FR_BUSY (1 << 3) /* UART busy */ 66 #define UART_FR_RXFE (1 << 4) /* Receive FIFO empty */ 67 #define UART_FR_TXFF (1 << 5) /* Transmit FIFO full */ 68 #define UART_FR_RXFF (1 << 6) /* Receive FIFO full */ 69 #define UART_FR_TXFE (1 << 7) /* Transmit FIFO empty */ 70 #define UART_FR_RI (1 << 8) /* Ring indicator */ 71 #define UART_ILPR 0x20 /* IrDA low-power counter register */ 72 #define UART_ILPR_ILPDVSR ((x) & 0xf) /* IrDA low-power divisor */ 73 #define UART_IBRD 0x24 /* Integer baud rate register */ 74 #define UART_IBRD_DIVINT ((x) & 0xff) /* Integer baud rate divisor */ 75 #define UART_FBRD 0x28 /* Fractional baud rate register */ 76 #define UART_FBRD_DIVFRAC ((x) & 0x3f) /* Fractional baud rate divisor */ 77 #define UART_LCR_H 0x2c /* Line control register */ 78 #define UART_LCR_H_BRK (1 << 0) /* Send break */ 79 #define UART_LCR_H_PEN (1 << 1) /* Parity enable */ 80 #define UART_LCR_H_EPS (1 << 2) /* Even parity select */ 81 #define UART_LCR_H_STP2 (1 << 3) /* Two stop bits select */ 82 #define UART_LCR_H_FEN (1 << 4) /* Enable FIFOs */ 83 #define UART_LCR_H_WLEN5 (0x0 << 5) /* Word length: 5 bits */ 84 #define UART_LCR_H_WLEN6 (0x1 << 5) /* Word length: 6 bits */ 85 #define UART_LCR_H_WLEN7 (0x2 << 5) /* Word length: 7 bits */ 86 #define UART_LCR_H_WLEN8 (0x3 << 5) /* Word length: 8 bits */ 87 #define UART_LCR_H_SPS (1 << 7) /* Stick parity select */ 88 #define UART_CR 0x30 /* Control register */ 89 #define UART_CR_UARTEN (1 << 0) /* UART enable */ 90 #define UART_CR_SIREN (1 << 1) /* SIR enable */ 91 #define UART_CR_SIRLP (1 << 2) /* IrDA SIR low power mode */ 92 #define UART_CR_LBE (1 << 7) /* Loop back enable */ 93 #define UART_CR_TXE (1 << 8) /* Transmit enable */ 94 #define UART_CR_RXE (1 << 9) /* Receive enable */ 95 #define UART_CR_DTR (1 << 10) /* Data transmit enable */ 96 #define UART_CR_RTS (1 << 11) /* Request to send */ 97 #define UART_CR_OUT1 (1 << 12) 98 #define UART_CR_OUT2 (1 << 13) 99 #define UART_CR_CTSE (1 << 14) /* CTS hardware flow control enable */ 100 #define UART_CR_RTSE (1 << 15) /* RTS hardware flow control enable */ 101 #define UART_IFLS 0x34 /* Interrupt FIFO level select register */ 102 #define UART_IMSC 0x38 /* Interrupt mask set/clear register */ 103 #define UART_IMSC_RIMIM (1 << 0) 104 #define UART_IMSC_CTSMIM (1 << 1) 105 #define UART_IMSC_DCDMIM (1 << 2) 106 #define UART_IMSC_DSRMIM (1 << 3) 107 #define UART_IMSC_RXIM (1 << 4) 108 #define UART_IMSC_TXIM (1 << 5) 109 #define UART_IMSC_RTIM (1 << 6) 110 #define UART_IMSC_FEIM (1 << 7) 111 #define UART_IMSC_PEIM (1 << 8) 112 #define UART_IMSC_BEIM (1 << 9) 113 #define UART_IMSC_OEIM (1 << 10) 114 #define UART_RIS 0x3c /* Raw interrupt status register */ 115 #define UART_MIS 0x40 /* Masked interrupt status register */ 116 #define UART_ICR 0x44 /* Interrupt clear register */ 117 #define UART_DMACR 0x48 /* DMA control register */ 118 #define UART_SPACE 0x100 119 120 void pluartcnprobe(struct consdev *cp); 121 void pluartcninit(struct consdev *cp); 122 int pluartcngetc(dev_t dev); 123 void pluartcnputc(dev_t dev, int c); 124 void pluartcnpollc(dev_t dev, int on); 125 int pluart_param(struct tty *tp, struct termios *t); 126 void pluart_start(struct tty *); 127 void pluart_pwroff(struct pluart_softc *sc); 128 void pluart_diag(void *arg); 129 void pluart_raisedtr(void *arg); 130 void pluart_softint(void *arg); 131 struct pluart_softc *pluart_sc(dev_t dev); 132 133 /* XXX - we imitate 'com' serial ports and take over their entry points */ 134 /* XXX: These belong elsewhere */ 135 cdev_decl(com); 136 cdev_decl(pluart); 137 138 struct cfdriver pluart_cd = { 139 NULL, "pluart", DV_TTY 140 }; 141 142 bus_space_tag_t pluartconsiot; 143 bus_space_handle_t pluartconsioh; 144 bus_addr_t pluartconsaddr; 145 tcflag_t pluartconscflag = TTYDEF_CFLAG; 146 int pluartdefaultrate = B38400; 147 148 struct cdevsw pluartdev = 149 cdev_tty_init(3/*XXX NUART */ ,pluart); /* 12: serial port */ 150 151 void 152 pluart_attach_common(struct pluart_softc *sc, int console) 153 { 154 int maj; 155 156 if (console) { 157 /* Locate the major number. */ 158 for (maj = 0; maj < nchrdev; maj++) 159 if (cdevsw[maj].d_open == pluartopen) 160 break; 161 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 162 163 printf(": console"); 164 SET(sc->sc_hwflags, COM_HW_CONSOLE); 165 } 166 167 timeout_set(&sc->sc_diag_tmo, pluart_diag, sc); 168 timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc); 169 sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc); 170 171 if(sc->sc_si == NULL) 172 panic("%s: can't establish soft interrupt.", 173 sc->sc_dev.dv_xname); 174 175 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM)); 176 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff); 177 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, 178 bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) & 179 ~UART_LCR_H_FEN); 180 181 printf("\n"); 182 } 183 184 int 185 pluart_intr(void *arg) 186 { 187 struct pluart_softc *sc = arg; 188 bus_space_tag_t iot = sc->sc_iot; 189 bus_space_handle_t ioh = sc->sc_ioh; 190 struct tty *tp = sc->sc_tty; 191 u_int16_t is; 192 u_int16_t *p; 193 u_int16_t c; 194 195 is = bus_space_read_4(iot, ioh, UART_RIS); 196 bus_space_write_4(iot, ioh, UART_ICR, is); 197 198 if (sc->sc_tty == NULL) 199 return 0; 200 201 if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM)) 202 return 0; 203 204 if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) { 205 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 206 if (sc->sc_halt > 0) 207 wakeup(&tp->t_outq); 208 (*linesw[tp->t_line].l_start)(tp); 209 } 210 211 p = sc->sc_ibufp; 212 213 while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) { 214 c = bus_space_read_2(iot, ioh, UART_DR); 215 if (c & UART_DR_BE) { 216 #ifdef DDB 217 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 218 if (db_console) 219 db_enter(); 220 continue; 221 } 222 #endif 223 c = 0; 224 } 225 if (p >= sc->sc_ibufend) { 226 sc->sc_floods++; 227 if (sc->sc_errors++ == 0) 228 timeout_add_sec(&sc->sc_diag_tmo, 60); 229 } else { 230 *p++ = c; 231 if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) { 232 /* XXX */ 233 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 234 //bus_space_write_4(iot, ioh, IMXUART_UCR3, 235 // sc->sc_ucr3); 236 } 237 } 238 /* XXX - msr stuff ? */ 239 } 240 sc->sc_ibufp = p; 241 242 softintr_schedule(sc->sc_si); 243 244 return 1; 245 } 246 247 int 248 pluart_param(struct tty *tp, struct termios *t) 249 { 250 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 251 //bus_space_tag_t iot = sc->sc_iot; 252 //bus_space_handle_t ioh = sc->sc_ioh; 253 int ospeed = t->c_ospeed; 254 int error; 255 tcflag_t oldcflag; 256 257 258 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 259 return EINVAL; 260 261 switch (ISSET(t->c_cflag, CSIZE)) { 262 case CS5: 263 return EINVAL; 264 case CS6: 265 return EINVAL; 266 case CS7: 267 //CLR(sc->sc_ucr2, IMXUART_CR2_WS); 268 break; 269 case CS8: 270 //SET(sc->sc_ucr2, IMXUART_CR2_WS); 271 break; 272 } 273 // bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 274 275 /* 276 if (ISSET(t->c_cflag, PARENB)) { 277 SET(sc->sc_ucr2, IMXUART_CR2_PREN); 278 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 279 } 280 */ 281 /* STOPB - XXX */ 282 if (ospeed == 0) { 283 /* lower dtr */ 284 } 285 286 if (ospeed != 0) { 287 while (ISSET(tp->t_state, TS_BUSY)) { 288 ++sc->sc_halt; 289 error = ttysleep(tp, &tp->t_outq, 290 TTOPRI | PCATCH, "pluartprm"); 291 --sc->sc_halt; 292 if (error) { 293 pluart_start(tp); 294 return (error); 295 } 296 } 297 /* set speed */ 298 } 299 300 /* setup fifo */ 301 302 /* When not using CRTSCTS, RTS follows DTR. */ 303 /* sc->sc_dtr = MCR_DTR; */ 304 305 306 /* and copy to tty */ 307 tp->t_ispeed = t->c_ispeed; 308 tp->t_ospeed = t->c_ospeed; 309 oldcflag = tp->t_cflag; 310 tp->t_cflag = t->c_cflag; 311 312 /* 313 * If DCD is off and MDMBUF is changed, ask the tty layer if we should 314 * stop the device. 315 */ 316 /* XXX */ 317 318 pluart_start(tp); 319 320 return 0; 321 } 322 323 void 324 pluart_start(struct tty *tp) 325 { 326 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 327 bus_space_tag_t iot = sc->sc_iot; 328 bus_space_handle_t ioh = sc->sc_ioh; 329 u_int16_t fr; 330 int s; 331 332 s = spltty(); 333 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 334 goto out; 335 ttwakeupwr(tp); 336 if (tp->t_outq.c_cc == 0) 337 goto out; 338 SET(tp->t_state, TS_BUSY); 339 340 fr = bus_space_read_4(iot, ioh, UART_FR); 341 while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) { 342 bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); 343 fr = bus_space_read_4(iot, ioh, UART_FR); 344 } 345 out: 346 splx(s); 347 } 348 349 void 350 pluart_pwroff(struct pluart_softc *sc) 351 { 352 } 353 354 void 355 pluart_diag(void *arg) 356 { 357 struct pluart_softc *sc = arg; 358 int overflows, floods; 359 int s; 360 361 s = spltty(); 362 sc->sc_errors = 0; 363 overflows = sc->sc_overflows; 364 sc->sc_overflows = 0; 365 floods = sc->sc_floods; 366 sc->sc_floods = 0; 367 splx(s); 368 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", 369 sc->sc_dev.dv_xname, 370 overflows, overflows == 1 ? "" : "s", 371 floods, floods == 1 ? "" : "s"); 372 } 373 374 void 375 pluart_raisedtr(void *arg) 376 { 377 //struct pluart_softc *sc = arg; 378 379 //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 380 //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3); 381 } 382 383 void 384 pluart_softint(void *arg) 385 { 386 struct pluart_softc *sc = arg; 387 struct tty *tp; 388 u_int16_t *ibufp; 389 u_int16_t *ibufend; 390 int c; 391 int err; 392 int s; 393 394 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 395 return; 396 397 tp = sc->sc_tty; 398 s = spltty(); 399 400 ibufp = sc->sc_ibuf; 401 ibufend = sc->sc_ibufp; 402 403 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 404 splx(s); 405 return; 406 } 407 408 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 409 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 410 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 411 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 412 413 #if 0 414 if (ISSET(tp->t_cflag, CRTSCTS) && 415 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) { 416 /* XXX */ 417 SET(sc->sc_ucr3, IMXUART_CR3_DSR); 418 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, 419 sc->sc_ucr3); 420 } 421 #endif 422 423 splx(s); 424 425 while (ibufp < ibufend) { 426 c = *ibufp++; 427 /* 428 if (ISSET(c, IMXUART_RX_OVERRUN)) { 429 sc->sc_overflows++; 430 if (sc->sc_errors++ == 0) 431 timeout_add_sec(&sc->sc_diag_tmo, 60); 432 } 433 */ 434 /* This is ugly, but fast. */ 435 436 err = 0; 437 /* 438 if (ISSET(c, IMXUART_RX_PRERR)) 439 err |= TTY_PE; 440 if (ISSET(c, IMXUART_RX_FRMERR)) 441 err |= TTY_FE; 442 */ 443 c = (c & 0xff) | err; 444 (*linesw[tp->t_line].l_rint)(c, tp); 445 } 446 } 447 448 int 449 pluartopen(dev_t dev, int flag, int mode, struct proc *p) 450 { 451 int unit = DEVUNIT(dev); 452 struct pluart_softc *sc; 453 bus_space_tag_t iot; 454 bus_space_handle_t ioh; 455 struct tty *tp; 456 int s; 457 int error = 0; 458 459 if (unit >= pluart_cd.cd_ndevs) 460 return ENXIO; 461 sc = pluart_cd.cd_devs[unit]; 462 if (sc == NULL) 463 return ENXIO; 464 465 s = spltty(); 466 if (sc->sc_tty == NULL) 467 tp = sc->sc_tty = ttymalloc(0); 468 else 469 tp = sc->sc_tty; 470 471 splx(s); 472 473 tp->t_oproc = pluart_start; 474 tp->t_param = pluart_param; 475 tp->t_dev = dev; 476 477 if (!ISSET(tp->t_state, TS_ISOPEN)) { 478 SET(tp->t_state, TS_WOPEN); 479 ttychars(tp); 480 tp->t_iflag = TTYDEF_IFLAG; 481 tp->t_oflag = TTYDEF_OFLAG; 482 483 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 484 tp->t_cflag = pluartconscflag; 485 else 486 tp->t_cflag = TTYDEF_CFLAG; 487 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) 488 SET(tp->t_cflag, CLOCAL); 489 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) 490 SET(tp->t_cflag, CRTSCTS); 491 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) 492 SET(tp->t_cflag, MDMBUF); 493 tp->t_lflag = TTYDEF_LFLAG; 494 tp->t_ispeed = tp->t_ospeed = pluartdefaultrate; 495 496 s = spltty(); 497 498 sc->sc_initialize = 1; 499 pluart_param(tp, &tp->t_termios); 500 ttsetwater(tp); 501 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 502 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 503 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 504 505 iot = sc->sc_iot; 506 ioh = sc->sc_ioh; 507 508 #if 0 509 sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1); 510 sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2); 511 sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3); 512 sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4); 513 514 /* interrupt after one char on tx/rx */ 515 /* reference frequency divider: 1 */ 516 bus_space_write_4(iot, ioh, IMXUART_UFCR, 517 1 << IMXUART_FCR_TXTL_SH | 518 5 << IMXUART_FCR_RFDIV_SH | 519 1 << IMXUART_FCR_RXTL_SH); 520 521 bus_space_write_4(iot, ioh, IMXUART_UBIR, 522 (pluartdefaultrate / 100) - 1); 523 524 /* formula: clk / (rfdiv * 1600) */ 525 bus_space_write_4(iot, ioh, IMXUART_UBMR, 526 (clk_get_rate(sc->sc_clk) * 1000) / 1600); 527 528 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN); 529 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN); 530 bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 531 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 532 533 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */ 534 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 535 bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 536 #endif 537 538 SET(tp->t_state, TS_CARR_ON); /* XXX */ 539 540 541 } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) 542 return EBUSY; 543 else 544 s = spltty(); 545 546 if (DEVCUA(dev)) { 547 if (ISSET(tp->t_state, TS_ISOPEN)) { 548 splx(s); 549 return EBUSY; 550 } 551 sc->sc_cua = 1; 552 } else { 553 /* tty (not cua) device; wait for carrier if necessary */ 554 if (ISSET(flag, O_NONBLOCK)) { 555 if (sc->sc_cua) { 556 /* Opening TTY non-blocking... but the CUA is busy */ 557 splx(s); 558 return EBUSY; 559 } 560 } else { 561 while (sc->sc_cua || 562 (!ISSET(tp->t_cflag, CLOCAL) && 563 !ISSET(tp->t_state, TS_CARR_ON))) { 564 SET(tp->t_state, TS_WOPEN); 565 error = ttysleep(tp, &tp->t_rawq, 566 TTIPRI | PCATCH, ttopen); 567 /* 568 * If TS_WOPEN has been reset, that means the 569 * cua device has been closed. We don't want 570 * to fail in that case, 571 * so just go around again. 572 */ 573 if (error && ISSET(tp->t_state, TS_WOPEN)) { 574 CLR(tp->t_state, TS_WOPEN); 575 if (!sc->sc_cua && !ISSET(tp->t_state, 576 TS_ISOPEN)) 577 pluart_pwroff(sc); 578 splx(s); 579 return error; 580 } 581 } 582 } 583 } 584 splx(s); 585 return (*linesw[tp->t_line].l_open)(dev,tp,p); 586 } 587 588 int 589 pluartclose(dev_t dev, int flag, int mode, struct proc *p) 590 { 591 int unit = DEVUNIT(dev); 592 struct pluart_softc *sc = pluart_cd.cd_devs[unit]; 593 //bus_space_tag_t iot = sc->sc_iot; 594 //bus_space_handle_t ioh = sc->sc_ioh; 595 struct tty *tp = sc->sc_tty; 596 int s; 597 598 /* XXX This is for cons.c. */ 599 if (!ISSET(tp->t_state, TS_ISOPEN)) 600 return 0; 601 602 (*linesw[tp->t_line].l_close)(tp, flag, p); 603 s = spltty(); 604 if (ISSET(tp->t_state, TS_WOPEN)) { 605 /* tty device is waiting for carrier; drop dtr then re-raise */ 606 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 607 //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 608 timeout_add_sec(&sc->sc_dtr_tmo, 2); 609 } else { 610 /* no one else waiting; turn off the uart */ 611 pluart_pwroff(sc); 612 } 613 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 614 615 sc->sc_cua = 0; 616 splx(s); 617 ttyclose(tp); 618 619 return 0; 620 } 621 622 int 623 pluartread(dev_t dev, struct uio *uio, int flag) 624 { 625 struct tty *tty; 626 627 tty = pluarttty(dev); 628 if (tty == NULL) 629 return ENODEV; 630 631 return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 632 } 633 634 int 635 pluartwrite(dev_t dev, struct uio *uio, int flag) 636 { 637 struct tty *tty; 638 639 tty = pluarttty(dev); 640 if (tty == NULL) 641 return ENODEV; 642 643 return((*linesw[tty->t_line].l_write)(tty, uio, flag)); 644 } 645 646 int 647 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 648 { 649 struct pluart_softc *sc; 650 struct tty *tp; 651 int error; 652 653 sc = pluart_sc(dev); 654 if (sc == NULL) 655 return (ENODEV); 656 657 tp = sc->sc_tty; 658 if (tp == NULL) 659 return (ENXIO); 660 661 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 662 if (error >= 0) 663 return (error); 664 665 error = ttioctl(tp, cmd, data, flag, p); 666 if (error >= 0) 667 return (error); 668 669 switch(cmd) { 670 case TIOCSBRK: 671 break; 672 case TIOCCBRK: 673 break; 674 case TIOCSDTR: 675 break; 676 case TIOCCDTR: 677 break; 678 case TIOCMSET: 679 break; 680 case TIOCMBIS: 681 break; 682 case TIOCMBIC: 683 break; 684 case TIOCMGET: 685 break; 686 case TIOCGFLAGS: 687 break; 688 case TIOCSFLAGS: 689 error = suser(p); 690 if (error != 0) 691 return(EPERM); 692 break; 693 default: 694 return (ENOTTY); 695 } 696 697 return 0; 698 } 699 700 int 701 pluartstop(struct tty *tp, int flag) 702 { 703 return 0; 704 } 705 706 struct tty * 707 pluarttty(dev_t dev) 708 { 709 int unit; 710 struct pluart_softc *sc; 711 unit = DEVUNIT(dev); 712 if (unit >= pluart_cd.cd_ndevs) 713 return NULL; 714 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 715 if (sc == NULL) 716 return NULL; 717 return sc->sc_tty; 718 } 719 720 struct pluart_softc * 721 pluart_sc(dev_t dev) 722 { 723 int unit; 724 struct pluart_softc *sc; 725 unit = DEVUNIT(dev); 726 if (unit >= pluart_cd.cd_ndevs) 727 return NULL; 728 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 729 return sc; 730 } 731 732 733 /* serial console */ 734 void 735 pluartcnprobe(struct consdev *cp) 736 { 737 } 738 739 void 740 pluartcninit(struct consdev *cp) 741 { 742 } 743 744 int 745 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 746 { 747 static struct consdev pluartcons = { 748 NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL, 749 NODEV, CN_MIDPRI 750 }; 751 int maj; 752 753 if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh)) 754 return ENOMEM; 755 756 /* Disable FIFO. */ 757 bus_space_write_4(iot, pluartconsioh, UART_LCR_H, 758 bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN); 759 760 /* Look for major of com(4) to replace. */ 761 for (maj = 0; maj < nchrdev; maj++) 762 if (cdevsw[maj].d_open == comopen) 763 break; 764 if (maj == nchrdev) 765 return ENXIO; 766 767 cn_tab = &pluartcons; 768 cn_tab->cn_dev = makedev(maj, 0); 769 cdevsw[maj] = pluartdev; /* KLUDGE */ 770 771 pluartconsiot = iot; 772 pluartconsaddr = iobase; 773 pluartconscflag = cflag; 774 775 return 0; 776 } 777 778 int 779 pluartcngetc(dev_t dev) 780 { 781 int c; 782 int s; 783 s = splhigh(); 784 while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 785 UART_FR_RXFF) == 0) 786 ; 787 c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR); 788 splx(s); 789 return c; 790 } 791 792 void 793 pluartcnputc(dev_t dev, int c) 794 { 795 int s; 796 s = splhigh(); 797 while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 798 UART_FR_TXFE) == 0) 799 ; 800 bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c); 801 splx(s); 802 } 803 804 void 805 pluartcnpollc(dev_t dev, int on) 806 { 807 } 808