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