1 /* $NetBSD: ixp12x0_com.c,v 1.50 2022/07/21 10:09:20 andvar Exp $ */ 2 /* 3 * Copyright (c) 1998, 1999, 2001, 2002 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Ichiro FUKUHARA and Naoto Shimazaki. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by IWAMOTO Toshihiro. 11 * 12 * This code is derived from software contributed to The NetBSD Foundation 13 * by Charles M. Hannum. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1991 The Regents of the University of California. 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)com.c 7.5 (Berkeley) 5/16/91 66 */ 67 68 #include <sys/cdefs.h> 69 __KERNEL_RCSID(0, "$NetBSD: ixp12x0_com.c,v 1.50 2022/07/21 10:09:20 andvar Exp $"); 70 71 #include "opt_ddb.h" 72 #include "opt_kgdb.h" 73 74 #ifdef RND_COM 75 #include <sys/rndsource.h> 76 #endif 77 78 #include <sys/param.h> 79 #include <sys/systm.h> 80 #include <sys/types.h> 81 #include <sys/conf.h> 82 #include <sys/file.h> 83 #include <sys/device.h> 84 #include <sys/kernel.h> 85 #include <sys/kmem.h> 86 #include <sys/tty.h> 87 #include <sys/uio.h> 88 #include <sys/vnode.h> 89 #include <sys/kauth.h> 90 #include <sys/lwp.h> 91 92 #include <machine/intr.h> 93 #include <sys/bus.h> 94 95 #include <arm/ixp12x0/ixp12x0_comreg.h> 96 #include <arm/ixp12x0/ixp12x0_comvar.h> 97 #include <arm/ixp12x0/ixp12x0reg.h> 98 #include <arm/ixp12x0/ixp12x0var.h> 99 100 #include <arm/ixp12x0/ixpsipvar.h> 101 102 #include <dev/cons.h> 103 #include "ixpcom.h" 104 105 static int ixpcomparam(struct tty *, struct termios *); 106 static void ixpcomstart(struct tty *); 107 static int ixpcomhwiflow(struct tty *, int); 108 109 static u_int cflag2cr(tcflag_t); 110 static void ixpcom_iflush(struct ixpcom_softc *); 111 static void ixpcom_set_cr(struct ixpcom_softc *); 112 113 int ixpcomcngetc(dev_t); 114 void ixpcomcnputc(dev_t, int); 115 void ixpcomcnpollc(dev_t, int); 116 117 static void ixpcomsoft(void* arg); 118 inline static void ixpcom_txsoft(struct ixpcom_softc *, struct tty *); 119 inline static void ixpcom_rxsoft(struct ixpcom_softc *, struct tty *); 120 121 void ixpcomcnprobe(struct consdev *); 122 void ixpcomcninit(struct consdev *); 123 124 uint32_t ixpcom_cr = 0; /* tell cr to *_intr.c */ 125 uint32_t ixpcom_imask = 0; /* interrupt mask from *_intr.c */ 126 127 128 static struct ixpcom_cons_softc { 129 bus_space_tag_t sc_iot; 130 bus_space_handle_t sc_ioh; 131 bus_addr_t sc_baseaddr; 132 int sc_ospeed; 133 tcflag_t sc_cflag; 134 int sc_attached; 135 } ixpcomcn_sc; 136 137 static struct cnm_state ixpcom_cnm_state; 138 139 struct ixpcom_softc* ixpcom_sc = NULL; 140 141 extern struct cfdriver ixpcom_cd; 142 143 dev_type_open(ixpcomopen); 144 dev_type_close(ixpcomclose); 145 dev_type_read(ixpcomread); 146 dev_type_write(ixpcomwrite); 147 dev_type_ioctl(ixpcomioctl); 148 dev_type_stop(ixpcomstop); 149 dev_type_tty(ixpcomtty); 150 dev_type_poll(ixpcompoll); 151 152 const struct cdevsw ixpcom_cdevsw = { 153 .d_open = ixpcomopen, 154 .d_close = ixpcomclose, 155 .d_read = ixpcomread, 156 .d_write = ixpcomwrite, 157 .d_ioctl = ixpcomioctl, 158 .d_stop = ixpcomstop, 159 .d_tty = ixpcomtty, 160 .d_poll = ixpcompoll, 161 .d_mmap = nommap, 162 .d_kqfilter = ttykqfilter, 163 .d_discard = nodiscard, 164 .d_flag = D_TTY 165 }; 166 167 struct consdev ixpcomcons = { 168 NULL, NULL, ixpcomcngetc, ixpcomcnputc, ixpcomcnpollc, NULL, 169 NULL, NULL, NODEV, CN_NORMAL 170 }; 171 172 #ifndef DEFAULT_COMSPEED 173 #define DEFAULT_COMSPEED 38400 174 #endif 175 176 #define COMUNIT(x) TTUNIT(x) 177 #define COMDIALOUT(x) TTDIALOUT(x) 178 179 #define COM_ISALIVE(sc) ((sc)->enabled != 0 && \ 180 device_is_active((sc)->sc_dev)) 181 182 #define COM_BARRIER(t, h, f) bus_space_barrier((t), (h), 0, COM_NPORTS, (f)) 183 184 #define COM_LOCK(sc); 185 #define COM_UNLOCK(sc); 186 187 #define CFLAGS2CR_MASK (CR_PE | CR_OES | CR_SBS | CR_DSS | CR_BRD) 188 189 void 190 ixpcom_attach_subr(struct ixpcom_softc *sc) 191 { 192 struct tty *tp; 193 194 ixpcom_sc = sc; 195 196 /* force to use ixpcom0 for console */ 197 if (sc->sc_iot == ixpcomcn_sc.sc_iot 198 && sc->sc_baseaddr == ixpcomcn_sc.sc_baseaddr) { 199 ixpcomcn_sc.sc_attached = 1; 200 sc->sc_speed = IXPCOMSPEED2BRD(ixpcomcn_sc.sc_ospeed); 201 202 /* Make sure the console is always "hardwired". */ 203 /* XXX IXPCOM_SR should be checked */ 204 delay(10000); /* wait for output to finish */ 205 SET(sc->sc_hwflags, COM_HW_CONSOLE); 206 SET(sc->sc_swflags, TIOCFLAG_SOFTCAR); 207 } 208 209 tp = tty_alloc(); 210 tp->t_oproc = ixpcomstart; 211 tp->t_param = ixpcomparam; 212 tp->t_hwiflow = ixpcomhwiflow; 213 214 sc->sc_tty = tp; 215 sc->sc_rbuf = kmem_alloc(IXPCOM_RING_SIZE << 1, KM_SLEEP); 216 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 217 sc->sc_rbavail = IXPCOM_RING_SIZE; 218 sc->sc_ebuf = sc->sc_rbuf + (IXPCOM_RING_SIZE << 1); 219 sc->sc_tbc = 0; 220 221 sc->sc_rie = sc->sc_xie = 0; 222 ixpcom_cr = IXPCOMSPEED2BRD(DEFAULT_COMSPEED) 223 | CR_UE | sc->sc_rie | sc->sc_xie | DSS_8BIT; 224 225 tty_attach(tp); 226 227 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 228 int maj; 229 230 /* locate the major number */ 231 maj = cdevsw_lookup_major(&ixpcom_cdevsw); 232 233 cn_tab->cn_dev = makedev(maj, device_unit(sc->sc_dev)); 234 235 aprint_normal("%s: console\n", device_xname(sc->sc_dev)); 236 } 237 238 sc->sc_si = softint_establish(SOFTINT_SERIAL, ixpcomsoft, sc); 239 240 #ifdef RND_COM 241 rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev), 242 RND_TYPE_TTY, RND_FLAG_COLLECT_TIME| 243 RND_FLAG_ESTIMATE_TIME); 244 #endif 245 246 /* if there are no enable/disable functions, assume the device 247 is always enabled */ 248 if (!sc->enable) 249 sc->enabled = 1; 250 251 /* XXX configure register */ 252 /* xxx_config(sc) */ 253 254 SET(sc->sc_hwflags, COM_HW_DEV_OK); 255 } 256 257 static int 258 ixpcomparam(struct tty *tp, struct termios *t) 259 { 260 struct ixpcom_softc *sc 261 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev)); 262 uint32_t cr; 263 int s; 264 265 if (COM_ISALIVE(sc) == 0) 266 return (EIO); 267 268 cr = IXPCOMSPEED2BRD(t->c_ospeed); 269 270 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 271 return (EINVAL); 272 273 /* 274 * For the console, always force CLOCAL and !HUPCL, so that the port 275 * is always active. 276 */ 277 if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) || 278 ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 279 SET(t->c_cflag, CLOCAL); 280 CLR(t->c_cflag, HUPCL); 281 } 282 283 /* 284 * If there were no changes, don't do anything. This avoids dropping 285 * input and improves performance when all we did was frob things like 286 * VMIN and VTIME. 287 */ 288 if (tp->t_ospeed == t->c_ospeed && 289 tp->t_cflag == t->c_cflag) 290 return (0); 291 292 cr |= cflag2cr(t->c_cflag); 293 294 s = splserial(); 295 COM_LOCK(sc); 296 297 ixpcom_cr = (ixpcom_cr & ~CFLAGS2CR_MASK) | cr; 298 299 /* 300 * ixpcom don't have any hardware flow control. 301 * we skip it. 302 */ 303 304 /* And copy to tty. */ 305 tp->t_ispeed = 0; 306 tp->t_ospeed = t->c_ospeed; 307 tp->t_cflag = t->c_cflag; 308 309 if (!sc->sc_heldchange) { 310 if (sc->sc_tx_busy) { 311 sc->sc_heldtbc = sc->sc_tbc; 312 sc->sc_tbc = 0; 313 sc->sc_heldchange = 1; 314 } else 315 ixpcom_set_cr(sc); 316 } 317 318 COM_UNLOCK(sc); 319 splx(s); 320 321 /* 322 * Update the tty layer's idea of the carrier bit. 323 * We tell tty the carrier is always on. 324 */ 325 (void) (*tp->t_linesw->l_modem)(tp, 1); 326 327 #ifdef COM_DEBUG 328 if (com_debug) 329 comstatus(sc, "comparam "); 330 #endif 331 332 if (!ISSET(t->c_cflag, CHWFLOW)) { 333 if (sc->sc_tx_stopped) { 334 sc->sc_tx_stopped = 0; 335 ixpcomstart(tp); 336 } 337 } 338 339 return (0); 340 } 341 342 static int 343 ixpcomhwiflow(struct tty *tp, int block) 344 { 345 return (0); 346 } 347 348 static void 349 ixpcom_filltx(struct ixpcom_softc *sc) 350 { 351 bus_space_tag_t iot = sc->sc_iot; 352 bus_space_handle_t ioh = sc->sc_ioh; 353 int n; 354 355 n = 0; 356 while (bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR) { 357 if (n >= sc->sc_tbc) 358 break; 359 bus_space_write_4(iot, ioh, IXPCOM_DR, 360 0xff & *(sc->sc_tba + n)); 361 n++; 362 } 363 sc->sc_tbc -= n; 364 sc->sc_tba += n; 365 } 366 367 static void 368 ixpcomstart(struct tty *tp) 369 { 370 struct ixpcom_softc *sc 371 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev)); 372 int s; 373 374 if (COM_ISALIVE(sc) == 0) 375 return; 376 377 s = spltty(); 378 if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) 379 goto out; 380 if (sc->sc_tx_stopped) 381 goto out; 382 383 if (!ttypull(tp)) 384 goto out; 385 386 /* Grab the first contiguous region of buffer space. */ 387 { 388 u_char *tba; 389 int tbc; 390 391 tba = tp->t_outq.c_cf; 392 tbc = ndqb(&tp->t_outq, 0); 393 394 (void)splserial(); 395 COM_LOCK(sc); 396 397 sc->sc_tba = tba; 398 sc->sc_tbc = tbc; 399 } 400 401 SET(tp->t_state, TS_BUSY); 402 sc->sc_tx_busy = 1; 403 404 /* Enable transmit completion interrupts if necessary. */ 405 if (!ISSET(sc->sc_xie, CR_XIE)) { 406 SET(sc->sc_xie, CR_XIE); 407 ixpcom_set_cr(sc); 408 } 409 410 /* Output the first chunk of the contiguous buffer. */ 411 ixpcom_filltx(sc); 412 413 COM_UNLOCK(sc); 414 out: 415 splx(s); 416 return; 417 } 418 419 static void 420 ixpcom_break(struct ixpcom_softc *sc, int onoff) 421 { 422 if (onoff) 423 SET(ixpcom_cr, CR_BRK); 424 else 425 CLR(ixpcom_cr, CR_BRK); 426 if (!sc->sc_heldchange) { 427 if (sc->sc_tx_busy) { 428 sc->sc_heldtbc = sc->sc_tbc; 429 sc->sc_tbc = 0; 430 sc->sc_heldchange = 1; 431 } else 432 ixpcom_set_cr(sc); 433 } 434 } 435 436 static void 437 ixpcom_shutdown(struct ixpcom_softc *sc) 438 { 439 int s; 440 441 s = splserial(); 442 COM_LOCK(sc); 443 444 /* Clear any break condition set with TIOCSBRK. */ 445 ixpcom_break(sc, 0); 446 447 /* Turn off interrupts. */ 448 sc->sc_rie = sc->sc_xie = 0; 449 ixpcom_set_cr(sc); 450 451 if (sc->disable) { 452 #ifdef DIAGNOSTIC 453 if (!sc->enabled) 454 panic("ixpcom_shutdown: not enabled?"); 455 #endif 456 (*sc->disable)(sc); 457 sc->enabled = 0; 458 } 459 COM_UNLOCK(sc); 460 splx(s); 461 } 462 463 int 464 ixpcomopen(dev_t dev, int flag, int mode, struct lwp *l) 465 { 466 struct ixpcom_softc *sc; 467 struct tty *tp; 468 int s, s2; 469 int error; 470 471 sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 472 if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK) || 473 sc->sc_rbuf == NULL) 474 return (ENXIO); 475 476 if (!device_is_active(sc->sc_dev)) 477 return (ENXIO); 478 479 #ifdef KGDB 480 /* 481 * If this is the kgdb port, no other use is permitted. 482 */ 483 if (ISSET(sc->sc_hwflags, COM_HW_KGDB)) 484 return (EBUSY); 485 #endif 486 487 tp = sc->sc_tty; 488 489 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 490 return (EBUSY); 491 492 s = spltty(); 493 494 /* 495 * Do the following iff this is a first open. 496 */ 497 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 498 struct termios t; 499 500 tp->t_dev = dev; 501 502 s2 = splserial(); 503 COM_LOCK(sc); 504 505 if (sc->enable) { 506 if ((*sc->enable)(sc)) { 507 COM_UNLOCK(sc); 508 splx(s2); 509 splx(s); 510 printf("%s: device enable failed\n", 511 device_xname(sc->sc_dev)); 512 return (EIO); 513 } 514 sc->enabled = 1; 515 #if 0 516 /* XXXXXXXXXXXXXXX */ 517 com_config(sc); 518 #endif 519 } 520 521 /* Turn on interrupts. */ 522 SET(sc->sc_rie, CR_RIE); 523 ixpcom_set_cr(sc); 524 525 #if 0 526 /* Fetch the current modem control status, needed later. */ 527 sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr); 528 529 /* Clear PPS capture state on first open. */ 530 sc->sc_ppsmask = 0; 531 sc->ppsparam.mode = 0; 532 #endif 533 534 COM_UNLOCK(sc); 535 splx(s2); 536 537 /* 538 * Initialize the termios status to the defaults. Add in the 539 * sticky bits from TIOCSFLAGS. 540 */ 541 t.c_ispeed = 0; 542 if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { 543 t.c_ospeed = ixpcomcn_sc.sc_ospeed; 544 t.c_cflag = ixpcomcn_sc.sc_cflag; 545 } else { 546 t.c_ospeed = TTYDEF_SPEED; 547 t.c_cflag = TTYDEF_CFLAG; 548 } 549 if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) 550 SET(t.c_cflag, CLOCAL); 551 if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) 552 SET(t.c_cflag, CRTSCTS); 553 if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) 554 SET(t.c_cflag, MDMBUF); 555 /* Make sure ixpcomparam() will do something. */ 556 tp->t_ospeed = 0; 557 (void) ixpcomparam(tp, &t); 558 tp->t_iflag = TTYDEF_IFLAG; 559 tp->t_oflag = TTYDEF_OFLAG; 560 tp->t_lflag = TTYDEF_LFLAG; 561 ttychars(tp); 562 ttsetwater(tp); 563 564 s2 = splserial(); 565 COM_LOCK(sc); 566 567 /* Clear the input ring, and unblock. */ 568 sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf; 569 sc->sc_rbavail = IXPCOM_RING_SIZE; 570 ixpcom_iflush(sc); 571 CLR(sc->sc_rx_flags, RX_ANY_BLOCK); 572 573 #ifdef COM_DEBUG 574 if (ixpcom_debug) 575 comstatus(sc, "ixpcomopen "); 576 #endif 577 578 COM_UNLOCK(sc); 579 splx(s2); 580 } 581 582 splx(s); 583 584 error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); 585 if (error) 586 goto bad; 587 588 error = (*tp->t_linesw->l_open)(dev, tp); 589 if (error) 590 goto bad; 591 592 return (0); 593 594 bad: 595 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 596 /* 597 * We failed to open the device, and nobody else had it opened. 598 * Clean up the state as appropriate. 599 */ 600 ixpcom_shutdown(sc); 601 } 602 603 return (error); 604 } 605 606 int 607 ixpcomclose(dev_t dev, int flag, int mode, struct lwp *l) 608 { 609 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 610 struct tty *tp = sc->sc_tty; 611 612 /* XXX This is for cons.c. */ 613 if (!ISSET(tp->t_state, TS_ISOPEN)) 614 return (0); 615 616 (*tp->t_linesw->l_close)(tp, flag); 617 ttyclose(tp); 618 619 if (COM_ISALIVE(sc) == 0) 620 return (0); 621 622 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { 623 /* 624 * Although we got a last close, the device may still be in 625 * use; e.g. if this was the dialout node, and there are still 626 * processes waiting for carrier on the non-dialout node. 627 */ 628 ixpcom_shutdown(sc); 629 } 630 631 return (0); 632 } 633 634 int 635 ixpcomread(dev_t dev, struct uio *uio, int flag) 636 { 637 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 638 struct tty *tp = sc->sc_tty; 639 640 if (COM_ISALIVE(sc) == 0) 641 return (EIO); 642 643 return ((*tp->t_linesw->l_read)(tp, uio, flag)); 644 } 645 646 int 647 ixpcomwrite(dev_t dev, struct uio *uio, int flag) 648 { 649 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 650 struct tty *tp = sc->sc_tty; 651 652 if (COM_ISALIVE(sc) == 0) 653 return (EIO); 654 655 return ((*tp->t_linesw->l_write)(tp, uio, flag)); 656 } 657 658 int 659 ixpcompoll(dev_t dev, int events, struct lwp *l) 660 { 661 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 662 struct tty *tp = sc->sc_tty; 663 664 if (COM_ISALIVE(sc) == 0) 665 return (EIO); 666 667 return ((*tp->t_linesw->l_poll)(tp, events, l)); 668 } 669 670 struct tty * 671 ixpcomtty(dev_t dev) 672 { 673 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 674 struct tty *tp = sc->sc_tty; 675 676 return (tp); 677 } 678 679 int 680 ixpcomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 681 { 682 struct ixpcom_softc *sc = device_lookup_private(&ixpcom_cd, COMUNIT(dev)); 683 struct tty *tp = sc->sc_tty; 684 int error; 685 int s; 686 687 if (COM_ISALIVE(sc) == 0) 688 return (EIO); 689 690 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l); 691 if (error != EPASSTHROUGH) 692 return (error); 693 694 error = ttioctl(tp, cmd, data, flag, l); 695 if (error != EPASSTHROUGH) 696 return (error); 697 698 error = 0; 699 700 s = splserial(); 701 COM_LOCK(sc); 702 703 switch (cmd) { 704 case TIOCSBRK: 705 ixpcom_break(sc, 1); 706 break; 707 708 case TIOCCBRK: 709 ixpcom_break(sc, 0); 710 break; 711 712 case TIOCGFLAGS: 713 *(int *)data = sc->sc_swflags; 714 break; 715 716 case TIOCSFLAGS: 717 error = kauth_authorize_device_tty(l->l_cred, 718 KAUTH_DEVICE_TTY_PRIVSET, tp); 719 if (error) 720 break; 721 sc->sc_swflags = *(int *)data; 722 break; 723 724 default: 725 error = EPASSTHROUGH; 726 break; 727 } 728 729 COM_UNLOCK(sc); 730 splx(s); 731 732 return (error); 733 } 734 735 /* 736 * Stop output on a line. 737 */ 738 void 739 ixpcomstop(struct tty *tp, int flag) 740 { 741 struct ixpcom_softc *sc 742 = device_lookup_private(&ixpcom_cd, COMUNIT(tp->t_dev)); 743 int s; 744 745 s = splserial(); 746 COM_LOCK(sc); 747 if (ISSET(tp->t_state, TS_BUSY)) { 748 /* Stop transmitting at the next chunk. */ 749 sc->sc_tbc = 0; 750 sc->sc_heldtbc = 0; 751 if (!ISSET(tp->t_state, TS_TTSTOP)) 752 SET(tp->t_state, TS_FLUSH); 753 } 754 COM_UNLOCK(sc); 755 splx(s); 756 } 757 758 static u_int 759 cflag2cr(tcflag_t cflag) 760 { 761 u_int cr; 762 763 cr = (cflag & PARENB) ? CR_PE : 0; 764 cr |= (cflag & PARODD) ? CR_OES : 0; 765 cr |= (cflag & CSTOPB) ? CR_SBS : 0; 766 cr |= ((cflag & CSIZE) == CS8) ? DSS_8BIT : 0; 767 768 return (cr); 769 } 770 771 static void 772 ixpcom_iflush(struct ixpcom_softc *sc) 773 { 774 bus_space_tag_t iot = sc->sc_iot; 775 bus_space_handle_t ioh = sc->sc_ioh; 776 #ifdef DIAGNOSTIC 777 int reg; 778 #endif 779 int timo; 780 781 #ifdef DIAGNOSTIC 782 reg = 0xffff; 783 #endif 784 timo = 50000; 785 /* flush any pending I/O */ 786 while (ISSET(bus_space_read_4(iot, ioh, IXPCOM_SR), SR_RXR) 787 && --timo) 788 #ifdef DIAGNOSTIC 789 reg = 790 #else 791 (void) 792 #endif 793 bus_space_read_4(iot, ioh, IXPCOM_DR); 794 #ifdef DIAGNOSTIC 795 if (!timo) 796 printf("%s: com_iflush timeout %02x\n", device_xname(sc->sc_dev), 797 reg); 798 #endif 799 } 800 801 static void 802 ixpcom_set_cr(struct ixpcom_softc *sc) 803 { 804 /* XXX */ 805 ixpcom_cr &= ~(CR_RIE | CR_XIE); 806 ixpcom_cr |= sc->sc_rie | sc->sc_xie; 807 bus_space_write_4(sc->sc_iot, sc->sc_ioh, IXPCOM_CR, 808 ixpcom_cr & ~ixpcom_imask); 809 } 810 811 int 812 ixpcomcnattach(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t ioh, int ospeed, tcflag_t cflag) 813 { 814 int cr; 815 816 cn_tab = &ixpcomcons; 817 cn_init_magic(&ixpcom_cnm_state); 818 /* 819 * XXX 820 * 821 * ixpcom cannot detect a break. It can only detect framing 822 * errors. And, a sequence of "framing error, framing error" 823 * meens a break. So I made this hack: 824 * 825 * 1. Set default magic is a sequence of "BREAK, BREAK". 826 * 2. Tell cn_check_magic() a "framing error" as BREAK. 827 * 828 * see ixpcom_intr() too. 829 * 830 */ 831 /* default magic is a couple of BREAK. */ 832 cn_set_magic("\047\001\047\001"); 833 834 ixpcomcn_sc.sc_iot = iot; 835 ixpcomcn_sc.sc_ioh = ioh; 836 ixpcomcn_sc.sc_baseaddr = iobase; 837 ixpcomcn_sc.sc_ospeed = ospeed; 838 ixpcomcn_sc.sc_cflag = cflag; 839 840 cr = cflag2cr(cflag); 841 cr |= IXPCOMSPEED2BRD(ospeed); 842 cr |= CR_UE; 843 ixpcom_cr = cr; 844 845 /* enable the UART */ 846 bus_space_write_4(iot, iobase, IXPCOM_CR, cr); 847 848 return (0); 849 } 850 851 void 852 ixpcomcnprobe(struct consdev *cp) 853 { 854 cp->cn_pri = CN_REMOTE; 855 } 856 857 void 858 ixpcomcnpollc(dev_t dev, int on) 859 { 860 } 861 862 void 863 ixpcomcnputc(dev_t dev, int c) 864 { 865 int s; 866 bus_space_tag_t iot = ixpcomcn_sc.sc_iot; 867 bus_space_handle_t ioh = ixpcomcn_sc.sc_ioh; 868 869 s = splserial(); 870 871 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXR)) 872 ; 873 874 bus_space_write_4(iot, ioh, IXPCOM_DR, c); 875 876 #ifdef DEBUG 877 if (c == '\r') { 878 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_TXE)) 879 ; 880 } 881 #endif 882 883 splx(s); 884 } 885 886 int 887 ixpcomcngetc(dev_t dev) 888 { 889 int c; 890 int s; 891 bus_space_tag_t iot = ixpcomcn_sc.sc_iot; 892 bus_space_handle_t ioh = ixpcomcn_sc.sc_ioh; 893 894 s = splserial(); 895 896 while(!(bus_space_read_4(iot, ioh, IXPCOM_SR) & SR_RXR)) 897 ; 898 899 c = bus_space_read_4(iot, ioh, IXPCOM_DR); 900 c &= 0xff; 901 splx(s); 902 903 return (c); 904 } 905 906 inline static void 907 ixpcom_txsoft(struct ixpcom_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 ixpcom_rxsoft(struct ixpcom_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 lsr; 924 int code; 925 int s; 926 927 end = sc->sc_ebuf; 928 get = sc->sc_rbget; 929 scc = cc = IXPCOM_RING_SIZE - sc->sc_rbavail; 930 #if 0 931 if (cc == IXPCOM_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 lsr = get[1]; 941 if (ISSET(lsr, DR_ROR | DR_FRE | DR_PRE)) { 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(lsr, DR_FRE)) 951 SET(code, TTY_FE); 952 if (ISSET(lsr, DR_PRE)) 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 -= IXPCOM_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 COM_LOCK(sc); 993 994 cc = sc->sc_rbavail += scc - cc; 995 /* Buffers should be ok again, release possible block. */ 996 if (cc >= 1) { 997 if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { 998 CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); 999 SET(sc->sc_rie, CR_RIE); 1000 ixpcom_set_cr(sc); 1001 } 1002 if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) { 1003 CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED); 1004 #if 0 1005 com_hwiflow(sc); 1006 #endif 1007 } 1008 } 1009 COM_UNLOCK(sc); 1010 splx(s); 1011 } 1012 } 1013 1014 static void 1015 ixpcomsoft(void* arg) 1016 { 1017 struct ixpcom_softc *sc = arg; 1018 1019 if (COM_ISALIVE(sc) == 0) 1020 return; 1021 1022 if (sc->sc_rx_ready) { 1023 sc->sc_rx_ready = 0; 1024 ixpcom_rxsoft(sc, sc->sc_tty); 1025 } 1026 if (sc->sc_tx_done) { 1027 sc->sc_tx_done = 0; 1028 ixpcom_txsoft(sc, sc->sc_tty); 1029 } 1030 } 1031 1032 int 1033 ixpcomintr(void* arg) 1034 { 1035 struct ixpcom_softc *sc = arg; 1036 bus_space_tag_t iot = sc->sc_iot; 1037 bus_space_handle_t ioh = sc->sc_ioh; 1038 u_char *put, *end; 1039 u_int cc; 1040 u_int cr; 1041 u_int sr; 1042 uint32_t c; 1043 1044 if (COM_ISALIVE(sc) == 0) 1045 return (0); 1046 1047 COM_LOCK(sc); 1048 cr = bus_space_read_4(iot, ioh, IXPCOM_CR) & CR_UE; 1049 1050 if (!cr) { 1051 COM_UNLOCK(sc); 1052 return (0); 1053 } 1054 1055 sr = bus_space_read_4(iot, ioh, IXPCOM_SR); 1056 if (!ISSET(sr, SR_TXR | SR_RXR)) 1057 return (0); 1058 1059 /* 1060 * XXX 1061 * 1062 * ixpcom cannot detect a break. It can only detect framing 1063 * errors. And, a sequence of "framing error, framing error" 1064 * meens a break. So I made this hack: 1065 * 1066 * 1. Set default magic is a sequence of "BREAK, BREAK". 1067 * 2. Tell cn_check_magic() a "framing error" as BREAK. 1068 * 1069 * see ixpcomcnattach() too. 1070 * 1071 */ 1072 if (ISSET(sr, SR_FRE)) { 1073 cn_check_magic(sc->sc_tty->t_dev, 1074 CNC_BREAK, ixpcom_cnm_state); 1075 } 1076 1077 end = sc->sc_ebuf; 1078 put = sc->sc_rbput; 1079 cc = sc->sc_rbavail; 1080 1081 if (ISSET(sr, SR_RXR)) { 1082 if (!ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { 1083 while (cc > 0) { 1084 if (!ISSET(sr, SR_RXR)) 1085 break; 1086 c = bus_space_read_4(iot, ioh, IXPCOM_DR); 1087 if (ISSET(c, DR_FRE)) { 1088 cn_check_magic(sc->sc_tty->t_dev, 1089 CNC_BREAK, 1090 ixpcom_cnm_state); 1091 } 1092 put[0] = c & 0xff; 1093 put[1] = (c >> 8) & 0xff; 1094 cn_check_magic(sc->sc_tty->t_dev, 1095 put[0], ixpcom_cnm_state); 1096 put += 2; 1097 if (put >= end) 1098 put = sc->sc_rbuf; 1099 cc--; 1100 1101 sr = bus_space_read_4(iot, ioh, IXPCOM_SR); 1102 } 1103 1104 /* 1105 * Current string of incoming characters ended because 1106 * no more data was available or we ran out of space. 1107 * Schedule a receive event if any data was received. 1108 * If we're out of space, turn off receive interrupts. 1109 */ 1110 sc->sc_rbput = put; 1111 sc->sc_rbavail = cc; 1112 if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) 1113 sc->sc_rx_ready = 1; 1114 1115 /* 1116 * See if we are in danger of overflowing a buffer. If 1117 * so, use hardware flow control to ease the pressure. 1118 */ 1119 1120 /* but ixpcom cannot. X-( */ 1121 1122 /* 1123 * If we're out of space, disable receive interrupts 1124 * until the queue has drained a bit. 1125 */ 1126 if (!cc) { 1127 SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); 1128 CLR(sc->sc_rie, CR_RIE); 1129 ixpcom_set_cr(sc); 1130 } 1131 } else { 1132 #ifdef DIAGNOSTIC 1133 panic("ixpcomintr: we shouldn't reach here"); 1134 #endif 1135 CLR(sc->sc_rie, CR_RIE); 1136 ixpcom_set_cr(sc); 1137 } 1138 } 1139 1140 /* 1141 * Done handling any receive interrupts. See if data can be 1142 * transmitted as well. Schedule tx done event if no data left 1143 * and tty was marked busy. 1144 */ 1145 sr = bus_space_read_4(iot, ioh, IXPCOM_SR); 1146 if (ISSET(sr, SR_TXR)) { 1147 /* 1148 * If we've delayed a parameter change, do it now, and restart 1149 * output. 1150 */ 1151 if (sc->sc_heldchange) { 1152 ixpcom_set_cr(sc); 1153 sc->sc_heldchange = 0; 1154 sc->sc_tbc = sc->sc_heldtbc; 1155 sc->sc_heldtbc = 0; 1156 } 1157 1158 /* Output the next chunk of the contiguous buffer, if any. */ 1159 if (sc->sc_tbc > 0) { 1160 ixpcom_filltx(sc); 1161 } else { 1162 /* Disable transmit completion interrupts if necessary. */ 1163 if (ISSET(sc->sc_xie, CR_XIE)) { 1164 CLR(sc->sc_xie, CR_XIE); 1165 ixpcom_set_cr(sc); 1166 } 1167 if (sc->sc_tx_busy) { 1168 sc->sc_tx_busy = 0; 1169 sc->sc_tx_done = 1; 1170 } 1171 } 1172 } 1173 COM_UNLOCK(sc); 1174 1175 /* Wake up the poller. */ 1176 softint_schedule(sc->sc_si); 1177 1178 #ifdef RND_COM 1179 rnd_add_uint32(&sc->rnd_source, iir | lsr); 1180 #endif 1181 return (1); 1182 } 1183