1 /* $OpenBSD: pluart.c,v 1.7 2021/09/01 09:29:31 jan 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_diag(void *arg); 128 void pluart_raisedtr(void *arg); 129 void pluart_softint(void *arg); 130 struct pluart_softc *pluart_sc(dev_t dev); 131 132 /* XXX - we imitate 'com' serial ports and take over their entry points */ 133 /* XXX: These belong elsewhere */ 134 cdev_decl(com); 135 cdev_decl(pluart); 136 137 struct cfdriver pluart_cd = { 138 NULL, "pluart", DV_TTY 139 }; 140 141 bus_space_tag_t pluartconsiot; 142 bus_space_handle_t pluartconsioh; 143 bus_addr_t pluartconsaddr; 144 tcflag_t pluartconscflag = TTYDEF_CFLAG; 145 int pluartdefaultrate = B38400; 146 147 struct cdevsw pluartdev = 148 cdev_tty_init(3/*XXX NUART */ ,pluart); /* 12: serial port */ 149 150 void 151 pluart_attach_common(struct pluart_softc *sc, int console) 152 { 153 int maj; 154 155 if (console) { 156 /* Locate the major number. */ 157 for (maj = 0; maj < nchrdev; maj++) 158 if (cdevsw[maj].d_open == pluartopen) 159 break; 160 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); 161 162 printf(": console"); 163 SET(sc->sc_hwflags, COM_HW_CONSOLE); 164 } 165 166 timeout_set(&sc->sc_diag_tmo, pluart_diag, sc); 167 timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc); 168 sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc); 169 170 if(sc->sc_si == NULL) 171 panic("%s: can't establish soft interrupt.", 172 sc->sc_dev.dv_xname); 173 174 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM)); 175 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff); 176 bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, 177 bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) & 178 ~UART_LCR_H_FEN); 179 180 printf("\n"); 181 } 182 183 int 184 pluart_intr(void *arg) 185 { 186 struct pluart_softc *sc = arg; 187 bus_space_tag_t iot = sc->sc_iot; 188 bus_space_handle_t ioh = sc->sc_ioh; 189 struct tty *tp = sc->sc_tty; 190 u_int16_t is; 191 u_int16_t *p; 192 u_int16_t c; 193 194 is = bus_space_read_4(iot, ioh, UART_RIS); 195 bus_space_write_4(iot, ioh, UART_ICR, is); 196 197 if (sc->sc_tty == NULL) 198 return 0; 199 200 if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM)) 201 return 0; 202 203 if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) { 204 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 205 if (sc->sc_halt > 0) 206 wakeup(&tp->t_outq); 207 (*linesw[tp->t_line].l_start)(tp); 208 } 209 210 p = sc->sc_ibufp; 211 212 while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) { 213 c = bus_space_read_2(iot, ioh, UART_DR); 214 if (c & UART_DR_BE) { 215 #ifdef DDB 216 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 217 if (db_console) 218 db_enter(); 219 continue; 220 } 221 #endif 222 c = 0; 223 } 224 if (p >= sc->sc_ibufend) { 225 sc->sc_floods++; 226 if (sc->sc_errors++ == 0) 227 timeout_add_sec(&sc->sc_diag_tmo, 60); 228 } else { 229 *p++ = c; 230 if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) { 231 /* XXX */ 232 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 233 //bus_space_write_4(iot, ioh, IMXUART_UCR3, 234 // sc->sc_ucr3); 235 } 236 } 237 /* XXX - msr stuff ? */ 238 } 239 sc->sc_ibufp = p; 240 241 softintr_schedule(sc->sc_si); 242 243 return 1; 244 } 245 246 int 247 pluart_param(struct tty *tp, struct termios *t) 248 { 249 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 250 //bus_space_tag_t iot = sc->sc_iot; 251 //bus_space_handle_t ioh = sc->sc_ioh; 252 int ospeed = t->c_ospeed; 253 int error; 254 tcflag_t oldcflag; 255 256 257 if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 258 return EINVAL; 259 260 switch (ISSET(t->c_cflag, CSIZE)) { 261 case CS5: 262 return EINVAL; 263 case CS6: 264 return EINVAL; 265 case CS7: 266 //CLR(sc->sc_ucr2, IMXUART_CR2_WS); 267 break; 268 case CS8: 269 //SET(sc->sc_ucr2, IMXUART_CR2_WS); 270 break; 271 } 272 // bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 273 274 /* 275 if (ISSET(t->c_cflag, PARENB)) { 276 SET(sc->sc_ucr2, IMXUART_CR2_PREN); 277 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 278 } 279 */ 280 /* STOPB - XXX */ 281 if (ospeed == 0) { 282 /* lower dtr */ 283 } 284 285 if (ospeed != 0) { 286 while (ISSET(tp->t_state, TS_BUSY)) { 287 ++sc->sc_halt; 288 error = ttysleep(tp, &tp->t_outq, 289 TTOPRI | PCATCH, "pluartprm"); 290 --sc->sc_halt; 291 if (error) { 292 pluart_start(tp); 293 return (error); 294 } 295 } 296 /* set speed */ 297 } 298 299 /* setup fifo */ 300 301 /* When not using CRTSCTS, RTS follows DTR. */ 302 /* sc->sc_dtr = MCR_DTR; */ 303 304 305 /* and copy to tty */ 306 tp->t_ispeed = t->c_ispeed; 307 tp->t_ospeed = t->c_ospeed; 308 oldcflag = tp->t_cflag; 309 tp->t_cflag = t->c_cflag; 310 311 /* 312 * If DCD is off and MDMBUF is changed, ask the tty layer if we should 313 * stop the device. 314 */ 315 /* XXX */ 316 317 pluart_start(tp); 318 319 return 0; 320 } 321 322 void 323 pluart_start(struct tty *tp) 324 { 325 struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; 326 bus_space_tag_t iot = sc->sc_iot; 327 bus_space_handle_t ioh = sc->sc_ioh; 328 u_int16_t fr; 329 int s; 330 331 s = spltty(); 332 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 333 goto out; 334 ttwakeupwr(tp); 335 if (tp->t_outq.c_cc == 0) 336 goto out; 337 SET(tp->t_state, TS_BUSY); 338 339 fr = bus_space_read_4(iot, ioh, UART_FR); 340 while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) { 341 bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); 342 fr = bus_space_read_4(iot, ioh, UART_FR); 343 } 344 out: 345 splx(s); 346 } 347 348 void 349 pluart_diag(void *arg) 350 { 351 struct pluart_softc *sc = arg; 352 int overflows, floods; 353 int s; 354 355 s = spltty(); 356 sc->sc_errors = 0; 357 overflows = sc->sc_overflows; 358 sc->sc_overflows = 0; 359 floods = sc->sc_floods; 360 sc->sc_floods = 0; 361 splx(s); 362 log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n", 363 sc->sc_dev.dv_xname, 364 overflows, overflows == 1 ? "" : "s", 365 floods, floods == 1 ? "" : "s"); 366 } 367 368 void 369 pluart_raisedtr(void *arg) 370 { 371 //struct pluart_softc *sc = arg; 372 373 //SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 374 //bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3); 375 } 376 377 void 378 pluart_softint(void *arg) 379 { 380 struct pluart_softc *sc = arg; 381 struct tty *tp; 382 u_int16_t *ibufp; 383 u_int16_t *ibufend; 384 int c; 385 int err; 386 int s; 387 388 if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf) 389 return; 390 391 tp = sc->sc_tty; 392 s = spltty(); 393 394 ibufp = sc->sc_ibuf; 395 ibufend = sc->sc_ibufp; 396 397 if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) { 398 splx(s); 399 return; 400 } 401 402 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ? 403 sc->sc_ibufs[1] : sc->sc_ibufs[0]; 404 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 405 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 406 407 #if 0 408 if (ISSET(tp->t_cflag, CRTSCTS) && 409 !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) { 410 /* XXX */ 411 SET(sc->sc_ucr3, IMXUART_CR3_DSR); 412 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, 413 sc->sc_ucr3); 414 } 415 #endif 416 417 splx(s); 418 419 while (ibufp < ibufend) { 420 c = *ibufp++; 421 /* 422 if (ISSET(c, IMXUART_RX_OVERRUN)) { 423 sc->sc_overflows++; 424 if (sc->sc_errors++ == 0) 425 timeout_add_sec(&sc->sc_diag_tmo, 60); 426 } 427 */ 428 /* This is ugly, but fast. */ 429 430 err = 0; 431 /* 432 if (ISSET(c, IMXUART_RX_PRERR)) 433 err |= TTY_PE; 434 if (ISSET(c, IMXUART_RX_FRMERR)) 435 err |= TTY_FE; 436 */ 437 c = (c & 0xff) | err; 438 (*linesw[tp->t_line].l_rint)(c, tp); 439 } 440 } 441 442 int 443 pluartopen(dev_t dev, int flag, int mode, struct proc *p) 444 { 445 int unit = DEVUNIT(dev); 446 struct pluart_softc *sc; 447 bus_space_tag_t iot; 448 bus_space_handle_t ioh; 449 struct tty *tp; 450 int s; 451 int error = 0; 452 453 if (unit >= pluart_cd.cd_ndevs) 454 return ENXIO; 455 sc = pluart_cd.cd_devs[unit]; 456 if (sc == NULL) 457 return ENXIO; 458 459 s = spltty(); 460 if (sc->sc_tty == NULL) 461 tp = sc->sc_tty = ttymalloc(0); 462 else 463 tp = sc->sc_tty; 464 465 splx(s); 466 467 tp->t_oproc = pluart_start; 468 tp->t_param = pluart_param; 469 tp->t_dev = dev; 470 471 if (!ISSET(tp->t_state, TS_ISOPEN)) { 472 SET(tp->t_state, TS_WOPEN); 473 ttychars(tp); 474 tp->t_iflag = TTYDEF_IFLAG; 475 tp->t_oflag = TTYDEF_OFLAG; 476 477 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) 478 tp->t_cflag = pluartconscflag; 479 else 480 tp->t_cflag = TTYDEF_CFLAG; 481 if (ISSET(sc->sc_swflags, COM_SW_CLOCAL)) 482 SET(tp->t_cflag, CLOCAL); 483 if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS)) 484 SET(tp->t_cflag, CRTSCTS); 485 if (ISSET(sc->sc_swflags, COM_SW_MDMBUF)) 486 SET(tp->t_cflag, MDMBUF); 487 tp->t_lflag = TTYDEF_LFLAG; 488 tp->t_ispeed = tp->t_ospeed = pluartdefaultrate; 489 490 s = spltty(); 491 492 sc->sc_initialize = 1; 493 pluart_param(tp, &tp->t_termios); 494 ttsetwater(tp); 495 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0]; 496 sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER; 497 sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE; 498 499 iot = sc->sc_iot; 500 ioh = sc->sc_ioh; 501 502 #if 0 503 sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1); 504 sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2); 505 sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3); 506 sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4); 507 508 /* interrupt after one char on tx/rx */ 509 /* reference frequency divider: 1 */ 510 bus_space_write_4(iot, ioh, IMXUART_UFCR, 511 1 << IMXUART_FCR_TXTL_SH | 512 5 << IMXUART_FCR_RFDIV_SH | 513 1 << IMXUART_FCR_RXTL_SH); 514 515 bus_space_write_4(iot, ioh, IMXUART_UBIR, 516 (pluartdefaultrate / 100) - 1); 517 518 /* formula: clk / (rfdiv * 1600) */ 519 bus_space_write_4(iot, ioh, IMXUART_UBMR, 520 (clk_get_rate(sc->sc_clk) * 1000) / 1600); 521 522 SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN); 523 SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN); 524 bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1); 525 bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2); 526 527 /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */ 528 SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */ 529 bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 530 #endif 531 532 SET(tp->t_state, TS_CARR_ON); /* XXX */ 533 534 535 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0) 536 return EBUSY; 537 else 538 s = spltty(); 539 540 if (DEVCUA(dev)) { 541 if (ISSET(tp->t_state, TS_ISOPEN)) { 542 splx(s); 543 return EBUSY; 544 } 545 sc->sc_cua = 1; 546 } else { 547 /* tty (not cua) device; wait for carrier if necessary */ 548 if (ISSET(flag, O_NONBLOCK)) { 549 if (sc->sc_cua) { 550 /* Opening TTY non-blocking... but the CUA is busy */ 551 splx(s); 552 return EBUSY; 553 } 554 } else { 555 while (sc->sc_cua || 556 (!ISSET(tp->t_cflag, CLOCAL) && 557 !ISSET(tp->t_state, TS_CARR_ON))) { 558 SET(tp->t_state, TS_WOPEN); 559 error = ttysleep(tp, &tp->t_rawq, 560 TTIPRI | PCATCH, ttopen); 561 /* 562 * If TS_WOPEN has been reset, that means the 563 * cua device has been closed. We don't want 564 * to fail in that case, 565 * so just go around again. 566 */ 567 if (error && ISSET(tp->t_state, TS_WOPEN)) { 568 CLR(tp->t_state, TS_WOPEN); 569 splx(s); 570 return error; 571 } 572 } 573 } 574 } 575 splx(s); 576 return (*linesw[tp->t_line].l_open)(dev,tp,p); 577 } 578 579 int 580 pluartclose(dev_t dev, int flag, int mode, struct proc *p) 581 { 582 int unit = DEVUNIT(dev); 583 struct pluart_softc *sc = pluart_cd.cd_devs[unit]; 584 //bus_space_tag_t iot = sc->sc_iot; 585 //bus_space_handle_t ioh = sc->sc_ioh; 586 struct tty *tp = sc->sc_tty; 587 int s; 588 589 /* XXX This is for cons.c. */ 590 if (!ISSET(tp->t_state, TS_ISOPEN)) 591 return 0; 592 593 (*linesw[tp->t_line].l_close)(tp, flag, p); 594 s = spltty(); 595 if (ISSET(tp->t_state, TS_WOPEN)) { 596 /* tty device is waiting for carrier; drop dtr then re-raise */ 597 //CLR(sc->sc_ucr3, IMXUART_CR3_DSR); 598 //bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3); 599 timeout_add_sec(&sc->sc_dtr_tmo, 2); 600 } 601 CLR(tp->t_state, TS_BUSY | TS_FLUSH); 602 603 sc->sc_cua = 0; 604 splx(s); 605 ttyclose(tp); 606 607 return 0; 608 } 609 610 int 611 pluartread(dev_t dev, struct uio *uio, int flag) 612 { 613 struct tty *tty; 614 615 tty = pluarttty(dev); 616 if (tty == NULL) 617 return ENODEV; 618 619 return((*linesw[tty->t_line].l_read)(tty, uio, flag)); 620 } 621 622 int 623 pluartwrite(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_write)(tty, uio, flag)); 632 } 633 634 int 635 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 636 { 637 struct pluart_softc *sc; 638 struct tty *tp; 639 int error; 640 641 sc = pluart_sc(dev); 642 if (sc == NULL) 643 return (ENODEV); 644 645 tp = sc->sc_tty; 646 if (tp == NULL) 647 return (ENXIO); 648 649 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 650 if (error >= 0) 651 return (error); 652 653 error = ttioctl(tp, cmd, data, flag, p); 654 if (error >= 0) 655 return (error); 656 657 switch(cmd) { 658 case TIOCSBRK: 659 break; 660 case TIOCCBRK: 661 break; 662 case TIOCSDTR: 663 break; 664 case TIOCCDTR: 665 break; 666 case TIOCMSET: 667 break; 668 case TIOCMBIS: 669 break; 670 case TIOCMBIC: 671 break; 672 case TIOCMGET: 673 break; 674 case TIOCGFLAGS: 675 break; 676 case TIOCSFLAGS: 677 error = suser(p); 678 if (error != 0) 679 return(EPERM); 680 break; 681 default: 682 return (ENOTTY); 683 } 684 685 return 0; 686 } 687 688 int 689 pluartstop(struct tty *tp, int flag) 690 { 691 return 0; 692 } 693 694 struct tty * 695 pluarttty(dev_t dev) 696 { 697 int unit; 698 struct pluart_softc *sc; 699 unit = DEVUNIT(dev); 700 if (unit >= pluart_cd.cd_ndevs) 701 return NULL; 702 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 703 if (sc == NULL) 704 return NULL; 705 return sc->sc_tty; 706 } 707 708 struct pluart_softc * 709 pluart_sc(dev_t dev) 710 { 711 int unit; 712 struct pluart_softc *sc; 713 unit = DEVUNIT(dev); 714 if (unit >= pluart_cd.cd_ndevs) 715 return NULL; 716 sc = (struct pluart_softc *)pluart_cd.cd_devs[unit]; 717 return sc; 718 } 719 720 721 /* serial console */ 722 void 723 pluartcnprobe(struct consdev *cp) 724 { 725 } 726 727 void 728 pluartcninit(struct consdev *cp) 729 { 730 } 731 732 int 733 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag) 734 { 735 static struct consdev pluartcons = { 736 NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL, 737 NODEV, CN_MIDPRI 738 }; 739 int maj; 740 741 if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh)) 742 return ENOMEM; 743 744 /* Disable FIFO. */ 745 bus_space_write_4(iot, pluartconsioh, UART_LCR_H, 746 bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN); 747 748 /* Look for major of com(4) to replace. */ 749 for (maj = 0; maj < nchrdev; maj++) 750 if (cdevsw[maj].d_open == comopen) 751 break; 752 if (maj == nchrdev) 753 return ENXIO; 754 755 cn_tab = &pluartcons; 756 cn_tab->cn_dev = makedev(maj, 0); 757 cdevsw[maj] = pluartdev; /* KLUDGE */ 758 759 pluartconsiot = iot; 760 pluartconsaddr = iobase; 761 pluartconscflag = cflag; 762 763 return 0; 764 } 765 766 int 767 pluartcngetc(dev_t dev) 768 { 769 int c; 770 int s; 771 s = splhigh(); 772 while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 773 UART_FR_RXFF) == 0) 774 ; 775 c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR); 776 splx(s); 777 return c; 778 } 779 780 void 781 pluartcnputc(dev_t dev, int c) 782 { 783 int s; 784 s = splhigh(); 785 while((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) & 786 UART_FR_TXFE) == 0) 787 ; 788 bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c); 789 splx(s); 790 } 791 792 void 793 pluartcnpollc(dev_t dev, int on) 794 { 795 } 796