1 /* $OpenBSD: pluart.c,v 1.2 2018/08/12 18:32:18 kettenis 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 fr; 192 u_int16_t *p; 193 u_int16_t c; 194 195 bus_space_write_4(iot, ioh, UART_ICR, -1); 196 197 if (sc->sc_tty == NULL) 198 return(0); 199 200 fr = bus_space_read_4(iot, ioh, UART_FR); 201 if (ISSET(fr, UART_FR_TXFE) && ISSET(tp->t_state, TS_BUSY)) { 202 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 203 if (sc->sc_halt > 0) 204 wakeup(&tp->t_outq); 205 (*linesw[tp->t_line].l_start)(tp); 206 } 207 208 if(!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) 209 return 0; 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(&sc->sc_diag_tmo, 60 * hz); 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", 0); 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 330 int s; 331 s = spltty(); 332 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 333 goto out; 334 if (tp->t_outq.c_cc <= tp->t_lowat) { 335 if (ISSET(tp->t_state, TS_ASLEEP)) { 336 CLR(tp->t_state, TS_ASLEEP); 337 wakeup(&tp->t_outq); 338 } 339 if (tp->t_outq.c_cc == 0) 340 goto out; 341 selwakeup(&tp->t_wsel); 342 } 343 SET(tp->t_state, TS_BUSY); 344 345 if (ISSET(sc->sc_hwflags, COM_HW_FIFO)) { 346 u_char buffer[64]; /* largest fifo */ 347 int i, n; 348 349 n = q_to_b(&tp->t_outq, buffer, 350 min(sc->sc_fifolen, sizeof buffer)); 351 for (i = 0; i < n; i++) { 352 bus_space_write_4(iot, ioh, UART_DR, buffer[i]); 353 } 354 bzero(buffer, n); 355 } else if (tp->t_outq.c_cc != 0) 356 bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); 357 358 out: 359 splx(s); 360 } 361 362 void 363 pluart_pwroff(struct pluart_softc *sc) 364 { 365 } 366 367 void 368 pluart_diag(void *arg) 369 { 370 struct pluart_softc *sc = arg; 371 int overflows, floods; 372 int s; 373 374 s = spltty(); 375 sc->sc_errors = 0; 376 overflows = sc->sc_overflows; 377 sc->sc_overflows = 0; 378 floods = sc->sc_floods; 379 sc->sc_floods = 0; 380 splx(s); 381 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", 382 sc->sc_dev.dv_xname, 383 overflows, overflows == 1 ? "" : "s", 384 floods, floods == 1 ? "" : "s"); 385 } 386 387 void 388 pluart_raisedtr(void *arg) 389 { 390 //struct pluart_softc *sc = arg; 391 392 //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 393 //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3); 394 } 395 396 void 397 pluart_softint(void *arg) 398 { 399 struct pluart_softc *sc = arg; 400 struct tty *tp; 401 u_int16_t *ibufp; 402 u_int16_t *ibufend; 403 int c; 404 int err; 405 int s; 406 407 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 408 return; 409 410 tp = sc->sc_tty; 411 s = spltty(); 412 413 ibufp = sc->sc_ibuf; 414 ibufend = sc->sc_ibufp; 415 416 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 417 splx(s); 418 return; 419 } 420 421 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 422 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 423 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 424 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 425 426 #if 0 427 if (ISSET(tp->t_cflag, CRTSCTS) && 428 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) { 429 /* XXX */ 430 SET(sc->sc_ucr3, IMXUART_CR3_DSR); 431 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, 432 sc->sc_ucr3); 433 } 434 #endif 435 436 splx(s); 437 438 while (ibufp < ibufend) { 439 c = *ibufp++; 440 /* 441 if (ISSET(c, IMXUART_RX_OVERRUN)) { 442 sc->sc_overflows++; 443 if (sc->sc_errors++ == 0) 444 timeout_add(&sc->sc_diag_tmo, 60 * hz); 445 } 446 */ 447 /* This is ugly, but fast. */ 448 449 err = 0; 450 /* 451 if (ISSET(c, IMXUART_RX_PRERR)) 452 err |= TTY_PE; 453 if (ISSET(c, IMXUART_RX_FRMERR)) 454 err |= TTY_FE; 455 */ 456 c = (c & 0xff) | err; 457 (*linesw[tp->t_line].l_rint)(c, tp); 458 } 459 } 460 461 int 462 pluartopen(dev_t dev, int flag, int mode, struct proc *p) 463 { 464 int unit = DEVUNIT(dev); 465 struct pluart_softc *sc; 466 bus_space_tag_t iot; 467 bus_space_handle_t ioh; 468 struct tty *tp; 469 int s; 470 int error = 0; 471 472 if (unit >= pluart_cd.cd_ndevs) 473 return ENXIO; 474 sc = pluart_cd.cd_devs[unit]; 475 if (sc == NULL) 476 return ENXIO; 477 478 s = spltty(); 479 if (sc->sc_tty == NULL) 480 tp = sc->sc_tty = ttymalloc(0); 481 else 482 tp = sc->sc_tty; 483 484 splx(s); 485 486 tp->t_oproc = pluart_start; 487 tp->t_param = pluart_param; 488 tp->t_dev = dev; 489 490 if (!ISSET(tp->t_state, TS_ISOPEN)) { 491 SET(tp->t_state, TS_WOPEN); 492 ttychars(tp); 493 tp->t_iflag = TTYDEF_IFLAG; 494 tp->t_oflag = TTYDEF_OFLAG; 495 496 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 497 tp->t_cflag = pluartconscflag; 498 else 499 tp->t_cflag = TTYDEF_CFLAG; 500 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) 501 SET(tp->t_cflag, CLOCAL); 502 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) 503 SET(tp->t_cflag, CRTSCTS); 504 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) 505 SET(tp->t_cflag, MDMBUF); 506 tp->t_lflag = TTYDEF_LFLAG; 507 tp->t_ispeed = tp->t_ospeed = pluartdefaultrate; 508 509 s = spltty(); 510 511 sc->sc_initialize = 1; 512 pluart_param(tp, &tp->t_termios); 513 ttsetwater(tp); 514 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 515 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 516 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 517 518 iot = sc->sc_iot; 519 ioh = sc->sc_ioh; 520 521 #if 0 522 sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1); 523 sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2); 524 sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3); 525 sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4); 526 527 /* interrupt after one char on tx/rx */ 528 /* reference frequency divider: 1 */ 529 bus_space_write_4(iot, ioh, IMXUART_UFCR, 530 1 << IMXUART_FCR_TXTL_SH | 531 5 << IMXUART_FCR_RFDIV_SH | 532 1 << IMXUART_FCR_RXTL_SH); 533 534 bus_space_write_4(iot, ioh, IMXUART_UBIR, 535 (pluartdefaultrate / 100) - 1); 536 537 /* formula: clk / (rfdiv * 1600) */ 538 bus_space_write_4(iot, ioh, IMXUART_UBMR, 539 (clk_get_rate(sc->sc_clk) * 1000) / 1600); 540 541 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN); 542 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN); 543 bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 544 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 545 546 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */ 547 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 548 bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 549 #endif 550 551 SET(tp->t_state, TS_CARR_ON); /* XXX */ 552 553 554 } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0) 555 return EBUSY; 556 else 557 s = spltty(); 558 559 if (DEVCUA(dev)) { 560 if (ISSET(tp->t_state, TS_ISOPEN)) { 561 splx(s); 562 return EBUSY; 563 } 564 sc->sc_cua = 1; 565 } else { 566 /* tty (not cua) device; wait for carrier if necessary */ 567 if (ISSET(flag, O_NONBLOCK)) { 568 if (sc->sc_cua) { 569 /* Opening TTY non-blocking... but the CUA is busy */ 570 splx(s); 571 return EBUSY; 572 } 573 } else { 574 while (sc->sc_cua || 575 (!ISSET(tp->t_cflag, CLOCAL) && 576 !ISSET(tp->t_state, TS_CARR_ON))) { 577 SET(tp->t_state, TS_WOPEN); 578 error = ttysleep(tp, &tp->t_rawq, 579 TTIPRI | PCATCH, ttopen, 0); 580 /* 581 * If TS_WOPEN has been reset, that means the 582 * cua device has been closed. We don't want 583 * to fail in that case, 584 * so just go around again. 585 */ 586 if (error && ISSET(tp->t_state, TS_WOPEN)) { 587 CLR(tp->t_state, TS_WOPEN); 588 if (!sc->sc_cua && !ISSET(tp->t_state, 589 TS_ISOPEN)) 590 pluart_pwroff(sc); 591 splx(s); 592 return error; 593 } 594 } 595 } 596 } 597 splx(s); 598 return (*linesw[tp->t_line].l_open)(dev,tp,p); 599 } 600 601 int 602 pluartclose(dev_t dev, int flag, int mode, struct proc *p) 603 { 604 int unit = DEVUNIT(dev); 605 struct pluart_softc *sc = pluart_cd.cd_devs[unit]; 606 //bus_space_tag_t iot = sc->sc_iot; 607 //bus_space_handle_t ioh = sc->sc_ioh; 608 struct tty *tp = sc->sc_tty; 609 int s; 610 611 /* XXX This is for cons.c. */ 612 if (!ISSET(tp->t_state, TS_ISOPEN)) 613 return 0; 614 615 (*linesw[tp->t_line].l_close)(tp, flag, p); 616 s = spltty(); 617 if (ISSET(tp->t_state, TS_WOPEN)) { 618 /* tty device is waiting for carrier; drop dtr then re-raise */ 619 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 620 //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 621 timeout_add(&sc->sc_dtr_tmo, hz * 2); 622 } else { 623 /* no one else waiting; turn off the uart */ 624 pluart_pwroff(sc); 625 } 626 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 627 628 sc->sc_cua = 0; 629 splx(s); 630 ttyclose(tp); 631 632 return 0; 633 } 634 635 int 636 pluartread(dev_t dev, struct uio *uio, int flag) 637 { 638 struct tty *tty; 639 640 tty = pluarttty(dev); 641 if (tty == NULL) 642 return ENODEV; 643 644 return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 645 } 646 647 int 648 pluartwrite(dev_t dev, struct uio *uio, int flag) 649 { 650 struct tty *tty; 651 652 tty = pluarttty(dev); 653 if (tty == NULL) 654 return ENODEV; 655 656 return((*linesw[tty->t_line].l_write)(tty, uio, flag)); 657 } 658 659 int 660 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 661 { 662 struct pluart_softc *sc; 663 struct tty *tp; 664 int error; 665 666 sc = pluart_sc(dev); 667 if (sc == NULL) 668 return (ENODEV); 669 670 tp = sc->sc_tty; 671 if (tp == NULL) 672 return (ENXIO); 673 674 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 675 if (error >= 0) 676 return (error); 677 678 error = ttioctl(tp, cmd, data, flag, p); 679 if (error >= 0) 680 return (error); 681 682 switch(cmd) { 683 case TIOCSBRK: 684 break; 685 case TIOCCBRK: 686 break; 687 case TIOCSDTR: 688 break; 689 case TIOCCDTR: 690 break; 691 case TIOCMSET: 692 break; 693 case TIOCMBIS: 694 break; 695 case TIOCMBIC: 696 break; 697 case TIOCMGET: 698 break; 699 case TIOCGFLAGS: 700 break; 701 case TIOCSFLAGS: 702 error = suser(p); 703 if (error != 0) 704 return(EPERM); 705 break; 706 default: 707 return (ENOTTY); 708 } 709 710 return 0; 711 } 712 713 int 714 pluartstop(struct tty *tp, int flag) 715 { 716 return 0; 717 } 718 719 struct tty * 720 pluarttty(dev_t dev) 721 { 722 int unit; 723 struct pluart_softc *sc; 724 unit = DEVUNIT(dev); 725 if (unit >= pluart_cd.cd_ndevs) 726 return NULL; 727 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 728 if (sc == NULL) 729 return NULL; 730 return sc->sc_tty; 731 } 732 733 struct pluart_softc * 734 pluart_sc(dev_t dev) 735 { 736 int unit; 737 struct pluart_softc *sc; 738 unit = DEVUNIT(dev); 739 if (unit >= pluart_cd.cd_ndevs) 740 return NULL; 741 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 742 return sc; 743 } 744 745 746 /* serial console */ 747 void 748 pluartcnprobe(struct consdev *cp) 749 { 750 } 751 752 void 753 pluartcninit(struct consdev *cp) 754 { 755 } 756 757 int 758 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 759 { 760 static struct consdev pluartcons = { 761 NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL, 762 NODEV, CN_MIDPRI 763 }; 764 int maj; 765 766 if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh)) 767 return ENOMEM; 768 769 /* Disable FIFO. */ 770 bus_space_write_4(iot, pluartconsioh, UART_LCR_H, 771 bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN); 772 773 /* Look for major of com(4) to replace. */ 774 for (maj = 0; maj < nchrdev; maj++) 775 if (cdevsw[maj].d_open == comopen) 776 break; 777 if (maj == nchrdev) 778 return ENXIO; 779 780 cn_tab = &pluartcons; 781 cn_tab->cn_dev = makedev(maj, 0); 782 cdevsw[maj] = pluartdev; /* KLUDGE */ 783 784 pluartconsiot = iot; 785 pluartconsaddr = iobase; 786 pluartconscflag = cflag; 787 788 return 0; 789 } 790 791 int 792 pluartcngetc(dev_t dev) 793 { 794 int c; 795 int s; 796 s = splhigh(); 797 while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 798 UART_FR_RXFF) == 0) 799 ; 800 c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR); 801 splx(s); 802 return c; 803 } 804 805 void 806 pluartcnputc(dev_t dev, int c) 807 { 808 int s; 809 s = splhigh(); 810 while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 811 UART_FR_TXFE) == 0) 812 ; 813 bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c); 814 splx(s); 815 } 816 817 void 818 pluartcnpollc(dev_t dev, int on) 819 { 820 } 821