1 /* $Id: at91usart.c,v 1.13 2015/04/13 21:18:40 riastradh Exp $ */ 2 /* $NetBSD: at91usart.c,v 1.13 2015/04/13 21:18:40 riastradh Exp $ */ 3 4 /* 5 * Copyright (c) 2007 Embedtronics Oy. All rights reserved. 6 * 7 * Copyright (c) 1998, 1999, 2001, 2002, 2004 The NetBSD Foundation, Inc. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to The NetBSD Foundation 11 * by Jesse Off 12 * 13 * This code is derived from software contributed to The NetBSD Foundation 14 * by Ichiro FUKUHARA and Naoto Shimazaki. 15 * 16 * This code is derived from software contributed to The NetBSD Foundation 17 * by IWAMOTO Toshihiro. 18 * 19 * This code is derived from software contributed to The NetBSD Foundation 20 * by Charles M. Hannum. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the above copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 32 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 /* 45 * Copyright (c) 1991 The Regents of the University of California. 46 * All rights reserved. 47 * 48 * Redistribution and use in source and binary forms, with or without 49 * modification, are permitted provided that the following conditions 50 * are met: 51 * 1. Redistributions of source code must retain the above copyright 52 * notice, this list of conditions and the following disclaimer. 53 * 2. Redistributions in binary form must reproduce the above copyright 54 * notice, this list of conditions and the following disclaimer in the 55 * documentation and/or other materials provided with the distribution. 56 * 3. Neither the name of the University nor the names of its contributors 57 * may be used to endorse or promote products derived from this software 58 * without specific prior written permission. 59 * 60 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 61 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 62 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 63 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 64 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 65 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 66 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 67 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 68 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 69 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 70 * SUCH DAMAGE. 71 * 72 * @(#)com.c 7.5 (Berkeley) 5/16/91 73 */ 74 75 /* 76 * TODO: hardware flow control 77 */ 78 79 #include <sys/cdefs.h> 80 __KERNEL_RCSID(0, "$NetBSD: at91usart.c,v 1.13 2015/04/13 21:18:40 riastradh Exp $"); 81 82 #include "opt_ddb.h" 83 #include "opt_kgdb.h" 84 85 #ifdef RND_COM 86 #include <sys/rndsource.h> 87 #endif 88 89 #ifdef NOTYET 90 /* 91 * Override cnmagic(9) macro before including <sys/systm.h>. 92 * We need to know if cn_check_magic triggered debugger, so set a flag. 93 * Callers of cn_check_magic must declare int cn_trapped = 0; 94 * XXX: this is *ugly*! 95 */ 96 #define cn_trap() \ 97 do { \ 98 console_debugger(); \ 99 cn_trapped = 1; \ 100 } while (/* CONSTCOND */ 0) 101 #endif /* NOTYET */ 102 103 104 #include <sys/param.h> 105 #include <sys/systm.h> 106 #include <sys/types.h> 107 #include <sys/conf.h> 108 #include <sys/file.h> 109 #include <sys/device.h> 110 #include <sys/kernel.h> 111 #include <sys/tty.h> 112 #include <sys/uio.h> 113 #include <sys/vnode.h> 114 #include <sys/kauth.h> 115 116 #include <machine/intr.h> 117 #include <sys/bus.h> 118 119 #include <arm/at91/at91reg.h> 120 #include <arm/at91/at91var.h> 121 #include <arm/at91/at91usartreg.h> 122 #include <arm/at91/at91usartvar.h> 123 124 #include <dev/cons.h> 125 126 static int at91usart_param(struct tty *, struct termios *); 127 static void at91usart_start(struct tty *); 128 static int at91usart_hwiflow(struct tty *, int); 129 130 #if 0 131 static u_int cflag2lcrhi(tcflag_t); 132 #endif 133 static void at91usart_set(struct at91usart_softc *); 134 135 #if NOTYET 136 int at91usart_cn_getc(dev_t); 137 void at91usart_cn_putc(dev_t, int); 138 void at91usart_cn_pollc(dev_t, int); 139 void at91usart_cn_probe(struct consdev *); 140 void at91usart_cn_init(struct consdev *); 141 142 static struct at91usart_cons_softc { 143 bus_space_tag_t sc_iot; 144 bus_space_handle_t sc_ioh; 145 bus_addr_t sc_hwbase; 146 int sc_ospeed; 147 tcflag_t sc_cflag; 148 int sc_attached; 149 150 uint8_t *sc_rx_ptr; 151 uint8_t sc_rx_fifo[64]; 152 } usart_cn_sc; 153 154 static struct cnm_state at91usart_cnm_state; 155 #endif /* NOTYET */ 156 157 static void at91usart_soft(void* arg); 158 inline static void at91usart_txsoft(struct at91usart_softc *, struct tty *); 159 inline static void at91usart_rxsoft(struct at91usart_softc *, struct tty *, unsigned csr); 160 161 #define PDC_BLOCK_SIZE 64 162 163 //CFATTACH_DECL_NEW(at91usart, sizeof(struct at91usart_softc), 164 // at91usart_match, at91usart_attach, NULL, NULL); 165 166 //#define USART_DEBUG 10 167 168 #ifdef USART_DEBUG 169 int usart_debug = USART_DEBUG; 170 #define DPRINTFN(n,fmt) if (usart_debug >= (n)) printf fmt 171 #else 172 #define DPRINTFN(n,fmt) 173 #endif 174 175 extern struct cfdriver at91usart_cd; 176 177 dev_type_open(at91usart_open); 178 dev_type_close(at91usart_close); 179 dev_type_read(at91usart_read); 180 dev_type_write(at91usart_write); 181 dev_type_ioctl(at91usart_ioctl); 182 dev_type_stop(at91usart_stop); 183 dev_type_tty(at91usart_tty); 184 dev_type_poll(at91usart_poll); 185 186 const struct cdevsw at91usart_cdevsw = { 187 .d_open = at91usart_open, 188 .d_close = at91usart_close, 189 .d_read = at91usart_read, 190 .d_write = at91usart_write, 191 .d_ioctl = at91usart_ioctl, 192 .d_stop = at91usart_stop, 193 .d_tty = at91usart_tty, 194 .d_poll = at91usart_poll, 195 .d_mmap = nommap, 196 .d_kqfilter = ttykqfilter, 197 .d_discard = nodiscard, 198 .d_flag = D_TTY 199 }; 200 201 #if NOTYET 202 struct consdev at91usart_cons = { 203 at91usart_cn_probe, NULL, at91usart_cn_getc, at91usart_cn_putc, at91usart_cn_pollc, NULL, 204 NULL, NULL, NODEV, CN_REMOTE 205 }; 206 #endif /* NOTYET */ 207 208 #ifndef DEFAULT_COMSPEED 209 #define DEFAULT_COMSPEED 115200 210 #endif 211 212 #define COMUNIT(x) TTUNIT(x) 213 #define COMDIALOUT(x) TTDIALOUT(x) 214 215 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && device_is_active((sc)->sc_dev)) 216 217 static inline void 218 at91usart_writereg(struct at91usart_softc *sc, int reg, u_int val) 219 { 220 bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val); 221 } 222 223 static inline u_int 224 at91usart_readreg(struct at91usart_softc *sc, int reg) 225 { 226 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg); 227 } 228 #if 0 229 static int 230 at91usart_match(device_t parent, cfdata_t cf, void *aux) 231 { 232 if (strcmp(cf->cf_name, "at91usart") == 0) 233 return 1; 234 return 0; 235 } 236 #endif 237 static int at91usart_intr(void* arg); 238 239 void 240 at91usart_attach_subr(struct at91usart_softc *sc, struct at91bus_attach_args *sa) 241 { 242 struct tty *tp; 243 int err; 244 245 printf("\n"); 246 247 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, &sc->sc_ioh)) 248 panic("%s: Cannot map registers", device_xname(sc->sc_dev)); 249 250 sc->sc_iot = sa->sa_iot; 251 sc->sc_hwbase = sa->sa_addr; 252 sc->sc_dmat = sa->sa_dmat; 253 sc->sc_pid = sa->sa_pid; 254 255 /* allocate fifos */ 256 err = at91pdc_alloc_fifo(sc->sc_dmat, &sc->sc_rx_fifo, AT91USART_RING_SIZE, BUS_DMA_READ | BUS_DMA_STREAMING); 257 if (err) 258 panic("%s: cannot allocate rx fifo", device_xname(sc->sc_dev)); 259 260 err = at91pdc_alloc_fifo(sc->sc_dmat, &sc->sc_tx_fifo, AT91USART_RING_SIZE, BUS_DMA_WRITE | BUS_DMA_STREAMING); 261 if (err) 262 panic("%s: cannot allocate tx fifo", device_xname(sc->sc_dev)); 263 264 /* initialize uart */ 265 at91_peripheral_clock(sc->sc_pid, 1); 266 267 at91usart_writereg(sc, US_IDR, -1); 268 at91usart_writereg(sc, US_RTOR, 12); // 12-bit timeout 269 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS); 270 at91_intr_establish(sa->sa_pid, IPL_TTY, INTR_HIGH_LEVEL, at91usart_intr, sc); 271 USART_INIT(sc, 115200U); 272 273 #ifdef NOTYET 274 if (sc->sc_iot == usart_cn_sc.sc_iot 275 && sc->sc_hwbase == usart_cn_sc.sc_hwbase) { 276 usart_cn_sc.sc_attached = 1; 277 /* Make sure the console is always "hardwired". */ 278 delay(10000); /* wait for output to finish */ 279 SET(sc->sc_hwflags, COM_HW_CONSOLE); 280 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR); 281 SET(sc->sc_ier, USART_INT_RXRDY); 282 USARTREG(USART_IER) = USART_INT_RXRDY; // @@@@@ 283 } 284 #endif // NOTYET 285 286 tp = tty_alloc(); 287 tp->t_oproc = at91usart_start; 288 tp->t_param = at91usart_param; 289 tp->t_hwiflow = at91usart_hwiflow; 290 291 sc->sc_tty = tp; 292 293 tty_attach(tp); 294 295 #if NOTYET 296 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 297 int maj; 298 299 /* locate the major number */ 300 maj = cdevsw_lookup_major(&at91usart_cdevsw); 301 302 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev)); 303 304 aprint_normal("%s: console (maj %u min %u cn_dev %u)\n", 305 device_xname(sc->sc_dev), maj, device_unit(sc->sc_dev), 306 cn_tab->cn_dev); 307 } 308 #endif /* NOTYET */ 309 310 sc->sc_si = softint_establish(SOFTINT_SERIAL, at91usart_soft, sc); 311 312 #ifdef RND_COM 313 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 314 RND_TYPE_TTY, RND_FLAG_DEFAULT); 315 #endif 316 317 /* if there are no enable/disable functions, assume the device 318 is always enabled */ 319 if (!sc->enable) 320 sc->enabled = 1; 321 322 /* XXX configure register */ 323 /* xxx_config(sc) */ 324 325 SET(sc->sc_hwflags, COM_HW_DEV_OK); 326 } 327 328 static int 329 at91usart_param(struct tty *tp, struct termios *t) 330 { 331 struct at91usart_softc *sc 332 = device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev)); 333 int s; 334 335 if (COM_ISALIVE(sc) == 0) 336 return (EIO); 337 338 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 339 return (EINVAL); 340 341 /* 342 * For the console, always force CLOCAL and !HUPCL, so that the port 343 * is always active. 344 */ 345 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 346 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 347 SET(t->c_cflag, CLOCAL); 348 CLR(t->c_cflag, HUPCL); 349 } 350 351 /* 352 * If there were no changes, don't do anything. This avoids dropping 353 * input and improves performance when all we did was frob things like 354 * VMIN and VTIME. 355 */ 356 if (tp->t_ospeed == t->c_ospeed && 357 tp->t_cflag == t->c_cflag) 358 return (0); 359 360 s = spltty(); 361 362 sc->sc_brgr = (AT91_MSTCLK / 16 + t->c_ospeed / 2) / t->c_ospeed; 363 364 /* And copy to tty. */ 365 tp->t_ispeed = 0; 366 tp->t_ospeed = t->c_ospeed; 367 tp->t_cflag = t->c_cflag; 368 at91usart_set(sc); 369 370 splx(s); 371 372 /* 373 * Update the tty layer's idea of the carrier bit. 374 * We tell tty the carrier is always on. 375 */ 376 (void) (*tp->t_linesw->l_modem)(tp, 1); 377 378 #ifdef COM_DEBUG 379 if (com_debug) 380 comstatus(sc, "comparam "); 381 #endif 382 383 /* tell the upper layer about hwflow.. */ 384 if (sc->hwflow) 385 (*sc->hwflow)(sc, t->c_cflag); 386 387 return (0); 388 } 389 390 static int 391 at91usart_hwiflow(struct tty *tp, int block) 392 { 393 if (block) { 394 /* tty discipline wants to block */ 395 } else { 396 /* tty discipline wants to unblock */ 397 } 398 return (0); 399 } 400 401 static __inline void 402 at91usart_start_tx(struct at91usart_softc *sc) 403 { 404 if (!sc->start_tx) 405 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTEN); 406 else 407 (*sc->start_tx)(sc); 408 } 409 410 static __inline void 411 at91usart_stop_tx(struct at91usart_softc *sc) 412 { 413 if (!sc->stop_tx) 414 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS); 415 else 416 (*sc->stop_tx)(sc); 417 } 418 419 static __inline void 420 at91usart_rx_started(struct at91usart_softc *sc) 421 { 422 if (sc->rx_started) 423 (*sc->rx_started)(sc); 424 } 425 426 static __inline void 427 at91usart_rx_stopped(struct at91usart_softc *sc) 428 { 429 if (sc->rx_stopped) 430 (*sc->rx_stopped)(sc); 431 } 432 433 static __inline void 434 at91usart_rx_rts_ctl(struct at91usart_softc *sc, int enabled) 435 { 436 if (sc->rx_rts_ctl) 437 (*sc->rx_rts_ctl)(sc, enabled); 438 } 439 440 static void 441 at91usart_filltx(struct at91usart_softc *sc) 442 { 443 struct tty *tp = sc->sc_tty; 444 int len; 445 void *dst; 446 447 // post write handler 448 AT91PDC_FIFO_POSTWRITE(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, 449 &sc->sc_tx_fifo); 450 451 // copy more data to fifo: 452 if (sc->sc_tbc > 0 453 && (dst = AT91PDC_FIFO_WRPTR(&sc->sc_tx_fifo, &len)) != NULL) { 454 // copy data to fifo 455 if (len > sc->sc_tbc) 456 len = sc->sc_tbc; 457 memcpy(dst, sc->sc_tba, len); 458 sc->sc_tba += len; 459 if ((sc->sc_tbc -= len) <= 0) 460 CLR(tp->t_state, TS_BUSY); 461 // update fifo 462 AT91PDC_FIFO_WRITTEN(&sc->sc_tx_fifo, len); 463 // tell tty interface we've sent some bytes 464 ndflush(&tp->t_outq, len); 465 } 466 467 // start sending data... 468 if (AT91PDC_FIFO_PREWRITE(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, 469 US_PDC, &sc->sc_tx_fifo, PDC_BLOCK_SIZE)) { 470 at91usart_start_tx(sc); 471 SET(sc->sc_ier, US_CSR_TXEMPTY | US_CSR_ENDTX); 472 } else { 473 CLR(sc->sc_ier, US_CSR_ENDTX); 474 } 475 } 476 477 static void 478 at91usart_start(struct tty *tp) 479 { 480 struct at91usart_softc *sc 481 = device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev)); 482 int s; 483 484 if (COM_ISALIVE(sc) == 0) { 485 DPRINTFN(5, ("%s: %s / COM_ISALIVE == 0\n", device_xname(sc->sc_dev), __FUNCTION__)); 486 return; 487 } 488 489 s = spltty(); 490 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { 491 DPRINTFN(5, ("%s: %s: TS_BUSY || TS_TIMEOUT || TS_TTSTOP\n", device_xname(sc->sc_dev), __FUNCTION__)); 492 goto out; 493 } 494 495 if (!ttypull(tp)) 496 goto out; 497 498 /* Grab the first contiguous region of buffer space. */ 499 { 500 u_char *tba; 501 int tbc; 502 503 tba = tp->t_outq.c_cf; 504 tbc = ndqb(&tp->t_outq, 0); 505 506 sc->sc_tba = tba; 507 sc->sc_tbc = tbc; 508 } 509 510 SET(tp->t_state, TS_BUSY); 511 512 /* Output the first chunk of the contiguous buffer. */ 513 at91usart_filltx(sc); 514 at91usart_writereg(sc, US_IER, sc->sc_ier); 515 DPRINTFN(5, ("%s: %s, ier=%08x (csr=%08x)\n", device_xname(sc->sc_dev), __FUNCTION__, sc->sc_ier, at91usart_readreg(sc, US_CSR))); 516 517 out: 518 splx(s); 519 520 return; 521 } 522 523 static __inline__ void 524 at91usart_break(struct at91usart_softc *sc, int onoff) 525 { 526 at91usart_writereg(sc, US_CR, onoff ? US_CR_STTBRK : US_CR_STPBRK); 527 } 528 529 static void 530 at91usart_shutdown(struct at91usart_softc *sc) 531 { 532 int s; 533 534 s = spltty(); 535 536 /* turn of dma */ 537 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS); 538 at91usart_writereg(sc, US_PDC + PDC_TNCR, 0); 539 at91usart_writereg(sc, US_PDC + PDC_TCR, 0); 540 at91usart_writereg(sc, US_PDC + PDC_RNCR, 0); 541 at91usart_writereg(sc, US_PDC + PDC_RCR, 0); 542 543 /* Turn off interrupts. */ 544 at91usart_writereg(sc, US_IDR, -1); 545 546 /* Clear any break condition set with TIOCSBRK. */ 547 at91usart_break(sc, 0); 548 at91usart_set(sc); 549 550 if (sc->disable) { 551 #ifdef DIAGNOSTIC 552 if (!sc->enabled) 553 panic("at91usart_shutdown: not enabled?"); 554 #endif 555 (*sc->disable)(sc); 556 sc->enabled = 0; 557 } 558 splx(s); 559 } 560 561 int 562 at91usart_open(dev_t dev, int flag, int mode, struct lwp *l) 563 { 564 struct at91usart_softc *sc; 565 struct tty *tp; 566 int s; 567 int error; 568 569 sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 570 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK)) 571 return (ENXIO); 572 573 if (!device_is_active(sc->sc_dev)) 574 return (ENXIO); 575 576 #ifdef KGDB 577 /* 578 * If this is the kgdb port, no other use is permitted. 579 */ 580 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 581 return (EBUSY); 582 #endif 583 584 tp = sc->sc_tty; 585 586 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 587 return (EBUSY); 588 589 s = spltty(); 590 591 /* 592 * Do the following iff this is a first open. 593 */ 594 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 595 struct termios t; 596 597 tp->t_dev = dev; 598 599 if (sc->enable) { 600 if ((*sc->enable)(sc)) { 601 splx(s); 602 printf("%s: device enable failed\n", 603 device_xname(sc->sc_dev)); 604 return (EIO); 605 } 606 sc->enabled = 1; 607 #if 0 608 /* XXXXXXXXXXXXXXX */ 609 com_config(sc); 610 #endif 611 } 612 613 /* reset fifos: */ 614 AT91PDC_RESET_FIFO(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, &sc->sc_rx_fifo, 0); 615 AT91PDC_RESET_FIFO(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, &sc->sc_tx_fifo, 1); 616 617 /* reset receive */ 618 at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO); 619 620 /* Turn on interrupts. */ 621 sc->sc_ier = US_CSR_ENDRX|US_CSR_RXBUFF|US_CSR_TIMEOUT|US_CSR_RXBRK; 622 at91usart_writereg(sc, US_IER, sc->sc_ier); 623 624 /* enable DMA: */ 625 at91usart_writereg(sc, US_PDC + PDC_PTCR, PDC_PTCR_RXTEN); 626 627 /* 628 * Initialize the termios status to the defaults. Add in the 629 * sticky bits from TIOCSFLAGS. 630 */ 631 t.c_ispeed = 0; 632 /* if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 633 t.c_ospeed = usart_cn_sc.sc_ospeed; 634 t.c_cflag = usart_cn_sc.sc_cflag; 635 } else*/ { 636 t.c_ospeed = TTYDEF_SPEED; 637 t.c_cflag = TTYDEF_CFLAG; 638 } 639 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 640 SET(t.c_cflag, CLOCAL); 641 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 642 SET(t.c_cflag, CRTSCTS); 643 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 644 SET(t.c_cflag, MDMBUF); 645 646 /* Make sure at91usart_param() will do something. */ 647 tp->t_ospeed = 0; 648 (void) at91usart_param(tp, &t); 649 tp->t_iflag = TTYDEF_IFLAG; 650 tp->t_oflag = TTYDEF_OFLAG; 651 tp->t_lflag = TTYDEF_LFLAG; 652 ttychars(tp); 653 ttsetwater(tp); 654 655 /* and unblock. */ 656 CLR(sc->sc_rx_flags, RX_ANY_BLOCK); 657 658 #ifdef COM_DEBUG 659 if (at91usart_debug) 660 comstatus(sc, "at91usart_open "); 661 #endif 662 663 } 664 665 splx(s); 666 667 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 668 if (error) 669 goto bad; 670 671 error = (*tp->t_linesw->l_open)(dev, tp); 672 if (error) 673 goto bad; 674 675 return (0); 676 677 bad: 678 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 679 /* 680 * We failed to open the device, and nobody else had it opened. 681 * Clean up the state as appropriate. 682 */ 683 at91usart_shutdown(sc); 684 } 685 686 return (error); 687 } 688 689 int 690 at91usart_close(dev_t dev, int flag, int mode, struct lwp *l) 691 { 692 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 693 struct tty *tp = sc->sc_tty; 694 695 /* XXX This is for cons.c. */ 696 if (!ISSET(tp->t_state, TS_ISOPEN)) 697 return (0); 698 699 (*tp->t_linesw->l_close)(tp, flag); 700 ttyclose(tp); 701 702 if (COM_ISALIVE(sc) == 0) 703 return (0); 704 705 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 706 /* 707 * Although we got a last close, the device may still be in 708 * use; e.g. if this was the dialout node, and there are still 709 * processes waiting for carrier on the non-dialout node. 710 */ 711 at91usart_shutdown(sc); 712 } 713 714 return (0); 715 } 716 717 int 718 at91usart_read(dev_t dev, struct uio *uio, int flag) 719 { 720 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 721 struct tty *tp = sc->sc_tty; 722 723 if (COM_ISALIVE(sc) == 0) 724 return (EIO); 725 726 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 727 } 728 729 int 730 at91usart_write(dev_t dev, struct uio *uio, int flag) 731 { 732 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 733 struct tty *tp = sc->sc_tty; 734 735 if (COM_ISALIVE(sc) == 0) 736 return (EIO); 737 738 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 739 } 740 741 int 742 at91usart_poll(dev_t dev, int events, struct lwp *l) 743 { 744 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 745 struct tty *tp = sc->sc_tty; 746 747 if (COM_ISALIVE(sc) == 0) 748 return (EIO); 749 750 return ((*tp->t_linesw->l_poll)(tp, events, l)); 751 } 752 753 struct tty * 754 at91usart_tty(dev_t dev) 755 { 756 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 757 struct tty *tp = sc->sc_tty; 758 759 return (tp); 760 } 761 762 int 763 at91usart_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 764 { 765 struct at91usart_softc *sc = device_lookup_private(&at91usart_cd, COMUNIT(dev)); 766 struct tty *tp = sc->sc_tty; 767 int error; 768 int s; 769 770 if (COM_ISALIVE(sc) == 0) 771 return (EIO); 772 773 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 774 if (error != EPASSTHROUGH) 775 return (error); 776 777 error = ttioctl(tp, cmd, data, flag, l); 778 if (error != EPASSTHROUGH) 779 return (error); 780 781 error = 0; 782 783 s = spltty(); 784 785 switch (cmd) { 786 case TIOCSBRK: 787 at91usart_break(sc, 1); 788 break; 789 790 case TIOCCBRK: 791 at91usart_break(sc, 0); 792 break; 793 794 case TIOCGFLAGS: 795 *(int *)data = sc->sc_swflags; 796 break; 797 798 case TIOCSFLAGS: 799 error = kauth_authorize_device_tty(l->l_cred, 800 KAUTH_DEVICE_TTY_PRIVSET, tp); 801 if (error) 802 break; 803 sc->sc_swflags = *(int *)data; 804 break; 805 806 default: 807 error = EPASSTHROUGH; 808 break; 809 } 810 811 splx(s); 812 813 return (error); 814 } 815 816 /* 817 * Stop output on a line. 818 */ 819 void 820 at91usart_stop(struct tty *tp, int flag) 821 { 822 struct at91usart_softc *sc 823 = device_lookup_private(&at91usart_cd, COMUNIT(tp->t_dev)); 824 int s; 825 826 s = spltty(); 827 if (ISSET(tp->t_state, TS_BUSY)) { 828 /* Stop transmitting at the next chunk. */ 829 sc->sc_tbc = 0; 830 if (!ISSET(tp->t_state, TS_TTSTOP)) 831 SET(tp->t_state, TS_FLUSH); 832 } 833 splx(s); 834 } 835 836 #if 0 837 static u_int 838 cflag2lcrhi(tcflag_t cflag) 839 { 840 uint32_t mr; 841 842 switch (cflag & CSIZE) { 843 default: 844 mr = 0x0; 845 break; 846 } 847 #if 0 848 mr |= (cflag & PARENB) ? LinCtrlHigh_PEN : 0; 849 mr |= (cflag & PARODD) ? 0 : LinCtrlHigh_EPS; 850 mr |= (cflag & CSTOPB) ? LinCtrlHigh_STP2 : 0; 851 mr |= LinCtrlHigh_FEN; /* FIFO always enabled */ 852 #endif 853 mr |= USART_MR_PAR_NONE; 854 return (mr); 855 } 856 #endif 857 858 859 static void 860 at91usart_set(struct at91usart_softc *sc) 861 { 862 at91usart_writereg(sc, US_MR, US_MR_CHRL_8 | US_MR_PAR_NONE | US_MR_NBSTOP_1); 863 at91usart_writereg(sc, US_BRGR, sc->sc_brgr); 864 at91usart_writereg(sc, US_CR, US_CR_TXEN | US_CR_RXEN); // @@@ just in case 865 } 866 867 #if NOTYET 868 int 869 at91usart_cn_attach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh, 870 uint32_t mstclk, int ospeed, tcflag_t cflag) 871 { 872 cn_tab = &at91usart_cons; 873 cn_init_magic(&at91usart_cnm_state); 874 cn_set_magic("\047\001"); 875 876 usart_cn_sc.sc_iot = iot; 877 usart_cn_sc.sc_ioh = ioh; 878 usart_cn_sc.sc_hwbase = iobase; 879 usart_cn_sc.sc_ospeed = ospeed; 880 usart_cn_sc.sc_cflag = cflag; 881 882 USART_INIT(mstclk, ospeed); 883 884 return (0); 885 } 886 887 void 888 at91usart_cn_probe(struct consdev *cp) 889 { 890 cp->cn_pri = CN_REMOTE; 891 } 892 893 void 894 at91usart_cn_pollc(dev_t dev, int on) 895 { 896 if (on) { 897 // enable polling mode 898 USARTREG(US_IDR) = USART_INT_RXRDY; 899 } else { 900 // disable polling mode 901 USARTREG(US_IER) = USART_INT_RXRDY; 902 } 903 } 904 905 void 906 at91usart_cn_putc(dev_t dev, int c) 907 { 908 int s; 909 #if 0 910 bus_space_tag_t iot = usart_cn_sc.sc_iot; 911 bus_space_handle_t ioh = usart_cn_sc.sc_ioh; 912 #endif 913 s = spltty(); 914 915 USART_PUTC(c); 916 917 #ifdef DEBUG 918 if (c == '\r') { 919 while((USARTREG(USART_SR) & USART_SR_TXEMPTY) == 0) 920 ; 921 } 922 #endif 923 924 splx(s); 925 } 926 927 int 928 at91usart_cn_getc(dev_t dev) 929 { 930 int c, sr; 931 int s; 932 #if 0 933 bus_space_tag_t iot = usart_cn_sc.sc_iot; 934 bus_space_handle_t ioh = usart_cn_sc.sc_ioh; 935 #endif 936 937 s = spltty(); 938 939 while ((c = USART_PEEKC()) == -1) { 940 splx(s); 941 s = spltty(); 942 } 943 ; 944 sr = USARTREG(USART_SR); 945 if (ISSET(sr, USART_SR_FRAME) && c == 0) { 946 USARTREG(USART_CR) = USART_CR_RSTSTA; // reset status bits 947 c = CNC_BREAK; 948 } 949 #ifdef DDB 950 extern int db_active; 951 if (!db_active) 952 #endif 953 { 954 int cn_trapped = 0; /* unused */ 955 956 cn_check_magic(dev, c, at91usart_cnm_state); 957 } 958 splx(s); 959 960 c &= 0xff; 961 962 return (c); 963 } 964 #endif /* NOTYET */ 965 966 inline static void 967 at91usart_rxsoft(struct at91usart_softc *sc, struct tty *tp, unsigned csr) 968 { 969 u_char *start, *get, *end; 970 int cc; 971 972 AT91PDC_FIFO_POSTREAD(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, 973 &sc->sc_rx_fifo); 974 975 if (ISSET(csr, US_CSR_TIMEOUT | US_CSR_RXBRK)) 976 at91usart_rx_stopped(sc); 977 978 while ((start = AT91PDC_FIFO_RDPTR(&sc->sc_rx_fifo, &cc)) != NULL) { 979 int (*rint)(int, struct tty *) = tp->t_linesw->l_rint; 980 int code; 981 982 if (!ISSET(csr, US_CSR_TIMEOUT | US_CSR_RXBRK)) 983 at91usart_rx_started(sc); 984 985 for (get = start, end = start + cc; get < end; get++) { 986 code = *get; 987 if ((*rint)(code, tp) == -1) { 988 /* 989 * The line discipline's buffer is out of space. 990 */ 991 if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) { 992 /* 993 * We're either not using flow control, or the 994 * line discipline didn't tell us to block for 995 * some reason. Either way, we have no way to 996 * know when there's more space available, so 997 * just drop the rest of the data. 998 */ 999 get = end; 1000 printf("%s: receive missing data!\n", 1001 device_xname(sc->sc_dev)); 1002 } else { 1003 /* 1004 * Don't schedule any more receive processing 1005 * until the line discipline tells us there's 1006 * space available (through comhwiflow()). 1007 * Leave the rest of the data in the input 1008 * buffer. 1009 */ 1010 SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED); 1011 } 1012 break; 1013 } 1014 } 1015 1016 // tell we've read some bytes... 1017 AT91PDC_FIFO_READ(&sc->sc_rx_fifo, get - start); 1018 1019 if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) 1020 break; 1021 } 1022 1023 // h/w flow control hook: 1024 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 1025 at91usart_rx_rts_ctl(sc, (AT91PDC_FIFO_SPACE(&sc->sc_rx_fifo) > PDC_BLOCK_SIZE * 2)); 1026 1027 // write next pointer if USART is ready: 1028 if (AT91PDC_FIFO_PREREAD(sc->sc_iot, sc->sc_ioh, sc->sc_dmat, US_PDC, 1029 &sc->sc_rx_fifo, PDC_BLOCK_SIZE)) { 1030 SET(sc->sc_ier, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK); 1031 } else { 1032 CLR(sc->sc_ier, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK); 1033 } 1034 } 1035 1036 inline static void 1037 at91usart_txsoft(struct at91usart_softc *sc, struct tty *tp) 1038 { 1039 at91usart_filltx(sc); 1040 if (!ISSET(tp->t_state, TS_BUSY)) 1041 (*tp->t_linesw->l_start)(tp); 1042 } 1043 1044 1045 static void 1046 at91usart_soft(void* arg) 1047 { 1048 struct at91usart_softc *sc = arg; 1049 int s; 1050 u_int csr; 1051 1052 if (COM_ISALIVE(sc) == 0) 1053 return; 1054 1055 s = spltty(); 1056 csr = sc->sc_csr; 1057 while (csr != 0) { 1058 if ((csr &= sc->sc_ier) == 0) 1059 break; 1060 // splx(s); 1061 DPRINTFN(5, ("%s: %s / csr = 0x%08x\n", device_xname(sc->sc_dev), __FUNCTION__, csr)); 1062 if (ISSET(csr, US_CSR_ENDRX | US_CSR_RXBUFF | US_CSR_TIMEOUT | US_CSR_RXBRK)) { 1063 /* receive interrupt */ 1064 if (ISSET(csr, US_CSR_RXBRK)) { 1065 // break received! 1066 at91usart_writereg(sc, US_CR, US_CR_RSTSTA | US_CR_STTTO); 1067 } else if (ISSET(csr, US_CSR_TIMEOUT)) { 1068 // timeout received 1069 at91usart_writereg(sc, US_CR, US_CR_STTTO); 1070 } 1071 at91usart_rxsoft(sc, sc->sc_tty, csr); 1072 } 1073 if (ISSET(csr, US_CSR_TXEMPTY)) { 1074 at91usart_stop_tx(sc); 1075 CLR(sc->sc_ier, US_CSR_TXEMPTY); 1076 if (AT91PDC_FIFO_EMPTY(&sc->sc_tx_fifo)) { 1077 // everything sent! 1078 if (ISSET(sc->sc_tty->t_state, TS_FLUSH)) 1079 CLR(sc->sc_tty->t_state, TS_FLUSH); 1080 } 1081 } 1082 if (ISSET(csr, US_CSR_TXEMPTY | US_CSR_ENDTX)) { 1083 /* transmit interrupt! */ 1084 at91usart_txsoft(sc, sc->sc_tty); 1085 } 1086 // s = spltty(); 1087 csr = at91usart_readreg(sc, US_CSR); 1088 } 1089 sc->sc_csr = 0; 1090 at91usart_writereg(sc, US_IER, sc->sc_ier); // re-enable interrupts 1091 splx(s); 1092 } 1093 1094 1095 static int 1096 at91usart_intr(void* arg) 1097 { 1098 struct at91usart_softc *sc = arg; 1099 u_int csr, imr; 1100 1101 // get out if interrupts are not enabled 1102 imr = at91usart_readreg(sc, US_IMR); 1103 if (!imr) 1104 return 0; 1105 // get out if pending interrupt is not enabled 1106 csr = at91usart_readreg(sc, US_CSR); 1107 DPRINTFN(6,("%s: csr=%08X imr=%08X\n", device_xname(sc->sc_dev), csr, imr)); 1108 if (!ISSET(csr, imr)) 1109 return 0; 1110 1111 // ok, we DO have some interrupts to serve! let softint do it 1112 sc->sc_csr = csr; 1113 at91usart_writereg(sc, US_IDR, -1); 1114 1115 /* Wake up the poller. */ 1116 softint_schedule(sc->sc_si); 1117 1118 /* we're done for now */ 1119 return (1); 1120 1121 } 1122