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