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