static void nmdm_task_tty(void *arg, int pending __unused) { struct tty *tp, *otp; struct nmdmpart *np = arg; char c; tp = np->np_tty; tty_lock(tp); if (tty_gone(tp)) { tty_unlock(tp); return; } otp = np->np_other->np_tty; KASSERT(otp != NULL, ("NULL otp in nmdmstart")); KASSERT(otp != tp, ("NULL otp == tp nmdmstart")); if (np->np_other->np_dcd) { if (!tty_opened(tp)) { np->np_other->np_dcd = 0; ttydisc_modem(otp, 0); } } else { if (tty_opened(tp)) { np->np_other->np_dcd = 1; ttydisc_modem(otp, 1); } } /* This may happen when we are in detach process. */ if (tty_gone(otp)) { tty_unlock(otp); return; } while (ttydisc_rint_poll(otp) > 0) { if (np->np_rate && !np->np_quota) break; if (ttydisc_getc(tp, &c, 1) != 1) break; np->np_quota--; ttydisc_rint(otp, c, 0); } ttydisc_rint_done(otp); tty_unlock(tp); }
static void nmdm_close(struct tty *tp) { struct nmdmpart *np; struct nmdmpart *onp; struct tty *otp; np = tty_softc(tp); onp = np->np_other; otp = onp->np_tty; /* If second part is opened, do not destroy ourselves. */ if (tty_opened(otp)) return; /* Shut down self. */ tty_rel_gone(tp); /* Shut down second part. */ tty_lock(tp); onp = np->np_other; if (onp == NULL) return; otp = onp->np_tty; tty_rel_gone(otp); tty_lock(tp); }
void si_intr(void *arg) { struct si_softc *sc; struct si_port *pp; volatile struct si_channel *ccbp; struct tty *tp; volatile caddr_t maddr; BYTE op, ip; int x, card, port, n, i, isopen; volatile BYTE *z; BYTE c; sc = arg; mtx_assert(&Giant, MA_OWNED); DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n")); /* * When we get an int we poll all the channels and do ALL pending * work, not just the first one we find. This allows all cards to * share the same vector. * * XXX - But if we're sharing the vector with something that's NOT * a SI/XIO/SX card, we may be making more work for ourselves. */ for (card = 0; card < si_numunits; card++) { sc = devclass_get_softc(si_devclass, card); if (sc == NULL || sc->sc_type == SIEMPTY) continue; /* * First, clear the interrupt */ switch(sc->sc_type) { case SIHOST: maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; /* flag nothing pending */ *(maddr+SIINTCL) = 0x00; /* Set IRQ clear */ *(maddr+SIINTCL_CL) = 0x00; /* Clear IRQ clear */ break; case SIHOST2: maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; *(maddr+SIPLIRQCLR) = 0x00; *(maddr+SIPLIRQCLR) = 0x10; break; case SIPCI: maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; *(maddr+SIPCIINTCL) = 0x0; break; case SIJETPCI: /* fall through to JETISA case */ case SIJETISA: maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; *(maddr+SIJETINTCL) = 0x0; break; #ifdef DEV_EISA case SIEISA: maddr = sc->sc_maddr; ((volatile struct si_reg *)maddr)->int_pending = 0; (void)inb(sc->sc_iobase + 3); break; #endif case SIEMPTY: default: continue; } ((volatile struct si_reg *)maddr)->int_scounter = 0; /* * check each port */ for (pp = sc->sc_ports, port = 0; port < sc->sc_nport; pp++, port++) { ccbp = pp->sp_ccb; tp = pp->sp_tty; tty_lock(tp); /* * See if a command has completed ? */ if (ccbp->hi_stat != pp->sp_pend) { DPRINT((pp, DBG_INTR, "si_intr hi_stat = %s, pend = %s\n", si_cmdname(ccbp->hi_stat), si_cmdname(pp->sp_pend))); switch(pp->sp_pend) { case LOPEN: case MPEND: case MOPEN: case FCLOSE: case CONFIG: case SBREAK: case EBREAK: /* sleeping in si_command */ DPRINT((pp, DBG_INTR, "do wakeup\n")); wakeup(&pp->sp_state); break; } pp->sp_pend = ccbp->hi_stat; } /* * Continue on if it's closed */ if (ccbp->hi_stat == IDLE_CLOSE) { tty_unlock(tp); continue; } /* * Do modem state change if not a local device */ si_modem_state(pp, tp, ccbp->hi_ip); /* * Check to see if we should 'receive' characters. */ isopen = tty_opened(tp); /* * Do input break processing */ if (ccbp->hi_state & ST_BREAK) { if (isopen) ttydisc_rint(tp, 0, TRE_BREAK); ccbp->hi_state &= ~ST_BREAK; /* A Bit iffy this */ DPRINT((pp, DBG_INTR, "si_intr break\n")); } /* * Do RX stuff - if not open then dump any characters. * XXX: This is VERY messy and needs to be cleaned up. * * XXX: can we leave data in the host adapter buffer * when the clists are full? That may be dangerous * if the user cannot get an interrupt signal through. */ more_rx: if (!isopen) { DPRINT((pp, DBG_INTR, "intr1: not open\n")); ccbp->hi_rxopos = ccbp->hi_rxipos; goto end_rx; } #if 0 /* XXXMPSAFETTY */ /* * If the tty input buffers are blocked, stop emptying * the incoming buffers and let the auto flow control * assert.. */ if (tp->t_state & TS_TBLOCK) goto end_rx; #endif /* * Process read characters if not skipped above */ op = ccbp->hi_rxopos; ip = ccbp->hi_rxipos; c = ip - op; if (c == 0) goto end_rx; n = c & 0xff; if (n > 250) n = 250; DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", n, op, ip)); /* * Suck characters out of host card buffer into the * "input staging buffer" - so that we dont leave the * host card in limbo while we're possibly echoing * characters and possibly flushing input inside the * ldisc l_rint() routine. */ if (n <= SI_BUFFERSIZE - op) { z = ccbp->hi_rxbuf + op; si_vbcopy(z, si_rxbuf, n); op += n; } else { x = SI_BUFFERSIZE - op; z = ccbp->hi_rxbuf + op; si_vbcopy(z, si_rxbuf, x); z = ccbp->hi_rxbuf; si_vbcopy(z, si_rxbuf + x, n - x); op += n; } /* clear collected characters from buffer */ ccbp->hi_rxopos = op; /* * at this point... * n = number of chars placed in si_rxbuf */ if (0 && ttydisc_can_bypass(tp)) { i = ttydisc_rint_bypass(tp, (char *)si_rxbuf, n); if (i < n) pp->sp_delta_overflows += (n - i); } else { /* * It'd be nice to not have to go through the * function call overhead for each char here. * It'd be nice to block input it, saving a * loop here and the call/return overhead. */ for(x = 0; x < n; x++) { i = si_rxbuf[x]; if (ttydisc_rint(tp, i, 0) == -1) pp->sp_delta_overflows++; } } goto more_rx; /* try for more until RXbuf is empty */ end_rx: ttydisc_rint_done(tp); /* * Do TX stuff */ si_start(tp); tty_unlock(tp); } /* end of for (all ports on this controller) */ } /* end of for (all controllers) */ DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n")); }