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