static int dcons_detach(int port) { struct tty *tp; struct dcons_softc *dc; dc = &sc[port]; tp = dc->dev->si_tty; if (tp->t_state & TS_ISOPEN) { printf("dcons: still opened\n"); (*linesw[tp->t_line].l_close)(tp, 0); tp->t_gen++; ttyclose(tp); ttwakeup(tp); ttwwakeup(tp); } /* XXX * must wait until all device are closed. */ tsleep((void *)dc, PWAIT, "dcodtc", hz/4); destroy_dev(dc->dev); return(0); }
void ucomreadcb(struct usbd_xfer *xfer, void *p, usbd_status status) { struct ucom_softc *sc = (struct ucom_softc *)p; struct tty *tp = sc->sc_tty; int (*rint)(int c, struct tty *tp) = LINESW(tp, l_rint); usbd_status err; u_int32_t cc; u_char *cp; int s; DPRINTFN(5,("ucomreadcb: status=%d\n", status)); if (status == USBD_CANCELLED || status == USBD_IOERROR || usbd_is_dying(sc->sc_uparent)) { DPRINTF(("ucomreadcb: dying\n")); /* Send something to wake upper layer */ s = spltty(); (*rint)('\n', tp); ttwakeup(tp); splx(s); return; } if (status) { if (sc->sc_bulkin_pipe != NULL) { usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); /* XXX we should restart after some delay. */ return; } } usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL); DPRINTFN(5,("ucomreadcb: got %d chars, tp=%p\n", cc, tp)); if (sc->sc_methods->ucom_read != NULL) sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno, &cp, &cc); s = spltty(); /* Give characters to tty layer. */ while (cc-- > 0) { DPRINTFN(7,("ucomreadcb: char=0x%02x\n", *cp)); if ((*rint)(*cp++, tp) == -1) { /* XXX what should we do? */ printf("%s: lost %d chars\n", sc->sc_dev.dv_xname, cc); break; } } splx(s); err = ucomstartread(sc); if (err) { printf("%s: read start failed\n", sc->sc_dev.dv_xname); /* XXX what should we dow now? */ } }
int ucom_detach(struct ucom_softc *sc) { struct tty *tp = sc->sc_tty; int s; DPRINTF(("ucom_detach: sc = %p, tp = %p\n", sc, sc->sc_tty)); sc->sc_dying = 1; if (sc->sc_bulkin_pipe != NULL) usbd_abort_pipe(sc->sc_bulkin_pipe); if (sc->sc_bulkout_pipe != NULL) usbd_abort_pipe(sc->sc_bulkout_pipe); if (tp != NULL) { if (tp->t_state & TS_ISOPEN) { device_printf(sc->sc_dev, "still open, forcing close\n"); (*linesw[tp->t_line].l_close)(tp, 0); tp->t_gen++; ttyclose(tp); ttwakeup(tp); ttwwakeup(tp); } } else { DPRINTF(("ucom_detach: no tty\n")); return (0); } s = splusb(); if (--sc->sc_refcnt >= 0) { /* Wait for processes to go away. */ usb_detach_wait(USBDEV(sc->sc_dev)); } splx(s); destroy_dev(sc->dev); return (0); }
static void ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status) { struct ucom_softc *sc = (struct ucom_softc *)p; struct tty *tp = sc->sc_tty; struct ucom_buffer *ub; u_int32_t cc; u_char *cp; int s; ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty); SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link); if (status == USBD_CANCELLED || status == USBD_IOERROR || sc->sc_dying) { DPRINTF(("ucomreadcb: dying\n")); ub->ub_index = ub->ub_len = 0; /* Send something to wake upper layer */ s = spltty(); if (status != USBD_CANCELLED) { (tp->t_linesw->l_rint)('\n', tp); mutex_spin_enter(&tty_lock); /* XXX */ ttwakeup(tp); mutex_spin_exit(&tty_lock); /* XXX */ } splx(s); return; } if (status == USBD_STALLED) { usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); ucomsubmitread(sc, ub); return; } if (status != USBD_NORMAL_COMPLETION) { printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status)); return; } usbd_get_xfer_status(xfer, NULL, (void *)&cp, &cc, NULL); if (cc == 0) { aprint_normal_dev(sc->sc_dev, "ucomreadcb: zero length xfer!\n"); } KDASSERT(cp == ub->ub_data); #if defined(__NetBSD__) && NRND > 0 rnd_add_uint32(&sc->sc_rndsource, cc); #endif if (sc->sc_opening) { ucomsubmitread(sc, ub); return; } if (sc->sc_methods->ucom_read != NULL) { sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno, &cp, &cc); ub->ub_index = (u_int)(cp - ub->ub_data); } else ub->ub_index = 0; ub->ub_len = cc; SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_full, ub, ub_link); ucom_read_complete(sc); }
int ptcwrite(dev_t dev, struct uio *uio, int flag) { struct pt_softc *pti = pt_softc[minor(dev)]; struct tty *tp = pti->pt_tty; u_char *cp = NULL; int cc = 0, bufcc = 0; u_char buf[BUFSIZ]; size_t cnt = 0; int error = 0; again: if ((tp->t_state&TS_ISOPEN) == 0) goto block; if (pti->pt_flags & PF_REMOTE) { if (tp->t_canq.c_cc) goto block; while (uio->uio_resid > 0 && tp->t_canq.c_cc < TTYHOG - 1) { if (cc == 0) { cc = MIN(uio->uio_resid, BUFSIZ); cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc); if (cc > bufcc) bufcc = cc; cp = buf; error = uiomove(cp, cc, uio); if (error) goto done; /* check again for safety */ if ((tp->t_state&TS_ISOPEN) == 0) { error = EIO; goto done; } } if (cc) (void) b_to_q((char *)cp, cc, &tp->t_canq); cc = 0; } (void) putc(0, &tp->t_canq); ttwakeup(tp); wakeup(&tp->t_canq); goto done; } while (uio->uio_resid > 0) { if (cc == 0) { cc = MIN(uio->uio_resid, BUFSIZ); if (cc > bufcc) bufcc = cc; cp = buf; error = uiomove(cp, cc, uio); if (error) goto done; /* check again for safety */ if ((tp->t_state&TS_ISOPEN) == 0) { error = EIO; goto done; } } bufcc = cc; while (cc > 0) { if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && (tp->t_canq.c_cc > 0 || !ISSET(tp->t_lflag, ICANON))) { wakeup(&tp->t_rawq); goto block; } (*linesw[tp->t_line].l_rint)(*cp++, tp); cnt++; cc--; } cc = 0; } goto done; block: /* * Come here to wait for slave to open, for space * in outq, or space in rawq. */ if ((tp->t_state&TS_CARR_ON) == 0) { error = EIO; goto done; } if (flag & IO_NDELAY) { /* adjust for data copied in but not written */ uio->uio_resid += cc; if (cnt == 0) error = EWOULDBLOCK; goto done; } error = tsleep(&tp->t_rawq.c_cf, TTOPRI | PCATCH, ttyout, 0); if (error == 0) goto again; /* adjust for data copied in but not written */ uio->uio_resid += cc; done: if (bufcc) bzero(buf, bufcc); return (error); }
/* * cz_intr: * * Interrupt service routine. * * We either are receiving an interrupt directly from the board, or we are * in polling mode and it's time to poll. */ static int cz_intr(void *arg) { int rval = 0; u_int command, channel; struct cz_softc *cz = arg; struct cztty_softc *sc; struct tty *tp; while ((command = (CZ_PLX_READ(cz, PLX_LOCAL_PCI_DOORBELL) & 0xff))) { rval = 1; channel = CZ_FWCTL_READ(cz, BRDCTL_FWCMD_CHANNEL); /* XXX - is this needed? */ (void)CZ_FWCTL_READ(cz, BRDCTL_FWCMD_PARAM); /* now clear this interrupt, posslibly enabling another */ CZ_PLX_WRITE(cz, PLX_LOCAL_PCI_DOORBELL, command); if (cz->cz_ports == NULL) { #ifdef CZ_DEBUG printf("%s: interrupt on channel %d, but no channels\n", device_xname(cz->cz_dev), channel); #endif continue; } sc = &cz->cz_ports[channel]; if (sc->sc_channel == CZTTY_CHANNEL_DEAD) break; tp = sc->sc_tty; switch (command) { case C_CM_TXFEMPTY: /* transmit cases */ case C_CM_TXBEMPTY: case C_CM_TXLOWWM: case C_CM_INTBACK: if (!ISSET(tp->t_state, TS_ISOPEN)) { #ifdef CZ_DEBUG printf("%s: tx intr on closed channel %d\n", device_xname(cz->cz_dev), channel); #endif break; } if (cztty_transmit(sc, tp)) { /* * Do wakeup stuff here. */ mutex_spin_enter(&tty_lock); /* XXX */ ttwakeup(tp); mutex_spin_exit(&tty_lock); /* XXX */ wakeup(tp); } break; case C_CM_RXNNDT: /* receive cases */ case C_CM_RXHIWM: case C_CM_INTBACK2: /* from restart ?? */ #if 0 case C_CM_ICHAR: #endif if (!ISSET(tp->t_state, TS_ISOPEN)) { CZTTY_BUF_WRITE(sc, BUFCTL_RX_GET, CZTTY_BUF_READ(sc, BUFCTL_RX_PUT)); break; } if (cztty_receive(sc, tp)) { /* * Do wakeup stuff here. */ mutex_spin_enter(&tty_lock); /* XXX */ ttwakeup(tp); mutex_spin_exit(&tty_lock); /* XXX */ wakeup(tp); } break; case C_CM_MDCD: if (!ISSET(tp->t_state, TS_ISOPEN)) break; (void) (*tp->t_linesw->l_modem)(tp, ISSET(C_RS_DCD, CZTTY_CHAN_READ(sc, CHNCTL_RS_STATUS))); break; case C_CM_MDSR: case C_CM_MRI: case C_CM_MCTS: case C_CM_MRTS: break; case C_CM_IOCTLW: break; case C_CM_PR_ERROR: sc->sc_parity_errors++; goto error_common; case C_CM_FR_ERROR: sc->sc_framing_errors++; goto error_common; case C_CM_OVR_ERROR: sc->sc_overflows++; error_common: if (sc->sc_errors++ == 0) callout_reset(&sc->sc_diag_ch, 60 * hz, cztty_diag, sc); break; case C_CM_RXBRK: if (!ISSET(tp->t_state, TS_ISOPEN)) break; /* * A break is a \000 character with TTY_FE error * flags set. So TTY_FE by itself works. */ (*tp->t_linesw->l_rint)(TTY_FE, tp); mutex_spin_enter(&tty_lock); /* XXX */ ttwakeup(tp); mutex_spin_exit(&tty_lock); /* XXX */ wakeup(tp); break; default: #ifdef CZ_DEBUG printf("%s: channel %d: Unknown interrupt 0x%x\n", device_xname(cz->cz_dev), sc->sc_channel, command); #endif break; } } return (rval); }
/* * I/O ops */ static int ptcwrite(struct dev_write_args *ap) { cdev_t dev = ap->a_head.a_dev; struct tty *tp = dev->si_tty; u_char *cp = NULL; int cc = 0; u_char locbuf[BUFSIZ]; int cnt = 0; struct pt_ioctl *pti = dev->si_drv1; int error = 0; lwkt_gettoken(&tty_token); again: if ((tp->t_state&TS_ISOPEN) == 0) goto block; if (pti->pt_flags & PF_REMOTE) { if (tp->t_canq.c_cc) goto block; while ((ap->a_uio->uio_resid > 0 || cc > 0) && tp->t_canq.c_cc < TTYHOG - 1) { if (cc == 0) { cc = (int)szmin(ap->a_uio->uio_resid, BUFSIZ); cc = imin(cc, TTYHOG - 1 - tp->t_canq.c_cc); cp = locbuf; error = uiomove(cp, (size_t)cc, ap->a_uio); if (error) { lwkt_reltoken(&tty_token); return (error); } /* check again for safety */ if ((tp->t_state & TS_ISOPEN) == 0) { /* adjust as usual */ ap->a_uio->uio_resid += cc; lwkt_reltoken(&tty_token); return (EIO); } } if (cc > 0) { cc = b_to_q((char *)cp, cc, &tp->t_canq); /* * XXX we don't guarantee that the canq size * is >= TTYHOG, so the above b_to_q() may * leave some bytes uncopied. However, space * is guaranteed for the null terminator if * we don't fail here since (TTYHOG - 1) is * not a multiple of CBSIZE. */ if (cc > 0) break; } } /* adjust for data copied in but not written */ ap->a_uio->uio_resid += cc; clist_putc(0, &tp->t_canq); ttwakeup(tp); wakeup(TSA_PTS_READ(tp)); lwkt_reltoken(&tty_token); return (0); } while (ap->a_uio->uio_resid > 0 || cc > 0) { if (cc == 0) { cc = (int)szmin(ap->a_uio->uio_resid, BUFSIZ); cp = locbuf; error = uiomove(cp, (size_t)cc, ap->a_uio); if (error) { lwkt_reltoken(&tty_token); return (error); } /* check again for safety */ if ((tp->t_state & TS_ISOPEN) == 0) { /* adjust for data copied in but not written */ ap->a_uio->uio_resid += cc; lwkt_reltoken(&tty_token); return (EIO); } } while (cc > 0) { if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 && (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) { wakeup(TSA_HUP_OR_INPUT(tp)); goto block; } (*linesw[tp->t_line].l_rint)(*cp++, tp); cnt++; cc--; } cc = 0; } lwkt_reltoken(&tty_token); return (0); block: /* * Come here to wait for slave to open, for space * in outq, or space in rawq, or an empty canq. */ if ((tp->t_state & TS_CONNECTED) == 0) { /* adjust for data copied in but not written */ ap->a_uio->uio_resid += cc; lwkt_reltoken(&tty_token); return (EIO); } if (ap->a_ioflag & IO_NDELAY) { /* adjust for data copied in but not written */ ap->a_uio->uio_resid += cc; if (cnt == 0) { lwkt_reltoken(&tty_token); return (EWOULDBLOCK); } lwkt_reltoken(&tty_token); return (0); } error = tsleep(TSA_PTC_WRITE(tp), PCATCH, "ptcout", 0); if (error) { /* adjust for data copied in but not written */ ap->a_uio->uio_resid += cc; lwkt_reltoken(&tty_token); return (error); } goto again; }
/* * Open a zs serial (tty) port. */ int zsopen(dev_t dev, int flags, int mode, struct proc *p) { struct zstty_softc *zst; struct zs_chanstate *cs; struct tty *tp; int s; #if IPL_ZS != IPL_TTY int s2; #endif int error; zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); if (zst == NULL) return (ENXIO); tp = zst->zst_tty; cs = zst->zst_cs; /* If KGDB took the line, then tp==NULL */ if (tp == NULL) return (EBUSY); if (ISSET(tp->t_state, TS_ISOPEN) && ISSET(tp->t_state, TS_XCLUDE) && suser(p, 0) != 0) return (EBUSY); s = spltty(); /* * Do the following iff this is a first open. */ if (!ISSET(tp->t_state, TS_ISOPEN)) { struct termios t; tp->t_dev = dev; /* Call the power management hook. */ if (cs->enable) { if ((*cs->enable)(cs)) { splx(s); printf("%s: device enable failed\n", zst->zst_dev.dv_xname); return (EIO); } } /* * Initialize the termios status to the defaults. Add in the * sticky bits from TIOCSFLAGS. */ t.c_ispeed = 0; t.c_ospeed = cs->cs_defspeed; t.c_cflag = cs->cs_defcflag; if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL)) SET(t.c_cflag, CLOCAL); if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS)) SET(t.c_cflag, CRTSCTS); if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF)) SET(t.c_cflag, MDMBUF); #if IPL_ZS != IPL_TTY s2 = splzs(); #endif /* * Turn on receiver and status interrupts. * We defer the actual write of the register to zsparam(), * but we must make sure status interrupts are turned on by * the time zsparam() reads the initial rr0 state. */ SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE); /* Clear PPS capture state on first open. */ zst->zst_ppsmask = 0; #if IPL_ZS != IPL_TTY splx(s2); #endif /* Make sure zsparam will see changes. */ tp->t_ospeed = 0; (void)zsparam(tp, &t); /* * Note: zsparam has done: cflag, ispeed, ospeed * so we just need to do: iflag, oflag, lflag, cc * For "raw" mode, just leave all zeros. */ if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) { tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; } else { tp->t_iflag = 0; tp->t_oflag = 0; tp->t_lflag = 0; } ttychars(tp); ttsetwater(tp); if (ZSDIALOUT(dev)) SET(tp->t_state, TS_CARR_ON); else CLR(tp->t_state, TS_CARR_ON); #if IPL_ZS != IPL_TTY s2 = splzs(); #endif /* Clear the input ring, and unblock. */ zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; zst->zst_rbavail = zstty_rbuf_size; zs_iflush(cs); CLR(zst->zst_rx_flags, RX_ANY_BLOCK); zs_hwiflow(zst); #if IPL_ZS != IPL_TTY splx(s2); #endif } if (ZSDIALOUT(dev)) { if (ISSET(tp->t_state, TS_ISOPEN)) { /* someone already is dialed in... */ splx(s); return EBUSY; } cs->cs_cua = 1; } error = 0; /* wait for carrier if necessary */ if (ISSET(flags, O_NONBLOCK)) { if (!ZSDIALOUT(dev) && cs->cs_cua) { /* Opening TTY non-blocking... but the CUA is busy */ error = EBUSY; } } else while (cs->cs_cua || (!ISSET(tp->t_cflag, CLOCAL) && !ISSET(tp->t_state, TS_CARR_ON))) { int rr0; error = 0; SET(tp->t_state, TS_WOPEN); if (!ZSDIALOUT(dev) && !cs->cs_cua) { /* * Turn on DTR. We must always do this on non-CUA * devices, even if carrier is not present, because * otherwise we'd have to use TIOCSDTR immediately * after setting CLOCAL, which applications do not * expect. We always assert DTR while the device is * open unless explicitly requested to deassert it. */ #if IPL_ZS != IPL_TTY s2 = splzs(); #endif zs_modem(zst, 1); rr0 = zs_read_csr(cs); #if IPL_ZS != IPL_TTY splx(s2); #endif /* loop, turning on the device, until carrier present */ if (ISSET(rr0, ZSRR0_DCD) || ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR)) SET(tp->t_state, TS_CARR_ON); } if ((ISSET(tp->t_cflag, CLOCAL) || ISSET(tp->t_state, TS_CARR_ON)) && !cs->cs_cua) break; error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, ttopen, 0); if (!ZSDIALOUT(dev) && cs->cs_cua && error == EINTR) { error = 0; continue; } if (error) { if (!ISSET(tp->t_state, TS_ISOPEN)) { #if IPL_ZS != IPL_TTY s2 = splzs(); #endif zs_modem(zst, 0); #if IPL_ZS != IPL_TTY splx(s2); #endif CLR(tp->t_state, TS_WOPEN); ttwakeup(tp); } if (ZSDIALOUT(dev)) cs->cs_cua = 0; CLR(tp->t_state, TS_WOPEN); break; } if (!ZSDIALOUT(dev) && cs->cs_cua) continue; } splx(s); if (error == 0) error = ((*linesw[tp->t_line].l_open)(dev, tp, p)); if (error) goto bad; return (0); bad: if (!ISSET(tp->t_state, TS_ISOPEN)) { /* * We failed to open the device, and nobody else had it opened. * Clean up the state as appropriate. */ zs_shutdown(zst); } return (error); }
Static void ucomreadcb(usbd_xfer_handle xfer, usbd_private_handle p, usbd_status status) { struct ucom_softc *sc = (struct ucom_softc *)p; struct tty *tp = sc->sc_tty; int (*rint) (int c, struct tty *tp) = linesw[tp->t_line].l_rint; usbd_status err; u_int32_t cc; u_char *cp; int lostcc; int s; DPRINTF(("ucomreadcb: status = %d\n", status)); if (status != USBD_NORMAL_COMPLETION) { if (!(sc->sc_state & UCS_RXSTOP)) printf("%s: ucomreadcb: %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(status)); if (status == USBD_STALLED) usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe); /* XXX we should restart after some delay. */ return; } usbd_get_xfer_status(xfer, NULL, (void **)&cp, &cc, NULL); DPRINTF(("ucomreadcb: got %d chars, tp = %p\n", cc, tp)); if (cc == 0) goto resubmit; if (sc->sc_callback->ucom_read != NULL) sc->sc_callback->ucom_read(sc->sc_parent, sc->sc_portno, &cp, &cc); if (cc > sc->sc_ibufsize) { printf("%s: invalid receive data size, %d chars\n", USBDEVNAME(sc->sc_dev), cc); goto resubmit; } if (cc < 1) goto resubmit; s = spltty(); if (tp->t_state & TS_CAN_BYPASS_L_RINT) { if (tp->t_rawq.c_cc + cc > tp->t_ihiwat && (sc->sc_state & UCS_RTS_IFLOW || tp->t_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK)) ttyblock(tp); lostcc = b_to_q((char *)cp, cc, &tp->t_rawq); tp->t_rawcc += cc; ttwakeup(tp); if (tp->t_state & TS_TTSTOP && (tp->t_iflag & IXANY || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { tp->t_state &= ~TS_TTSTOP; tp->t_lflag &= ~FLUSHO; ucomstart(tp); } if (lostcc > 0) printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev), lostcc); } else { /* Give characters to tty layer. */ while (cc > 0) { DPRINTFN(7, ("ucomreadcb: char = 0x%02x\n", *cp)); if ((*rint)(*cp, tp) == -1) { /* XXX what should we do? */ printf("%s: lost %d chars\n", USBDEVNAME(sc->sc_dev), cc); break; } cc--; cp++; } } splx(s); resubmit: err = ucomstartread(sc); if (err) { printf("%s: read start failed\n", USBDEVNAME(sc->sc_dev)); /* XXX what should we dow now? */ } if ((sc->sc_state & UCS_RTS_IFLOW) && !ISSET(sc->sc_mcr, UMCR_RTS) && !(tp->t_state & TS_TBLOCK)) ucomctl(sc, UMCR_RTS, DMBIS); }
/* * NOTE: Must be called with tty_token held */ static void rp_do_receive(struct rp_port *rp, struct tty *tp, CHANNEL_t *cp, unsigned int ChanStatus) { unsigned int CharNStat; int ToRecv, wRecv, ch, ttynocopy; ASSERT_LWKT_TOKEN_HELD(&tty_token); ToRecv = sGetRxCnt(cp); if(ToRecv == 0) return; /* If status indicates there are errored characters in the FIFO, then enter status mode (a word in FIFO holds characters and status) */ if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { if(!(ChanStatus & STATMODE)) { ChanStatus |= STATMODE; sEnRxStatusMode(cp); } } /* if we previously entered status mode then read down the FIFO one word at a time, pulling apart the character and the status. Update error counters depending on status. */ if(ChanStatus & STATMODE) { while(ToRecv) { if(tp->t_state & TS_TBLOCK) { break; } CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp)); ch = CharNStat & 0xff; if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH)) ch |= TTY_FE; else if (CharNStat & STMPARITYH) ch |= TTY_PE; else if (CharNStat & STMRCVROVRH) rp->rp_overflows++; (*linesw[tp->t_line].l_rint)(ch, tp); ToRecv--; } /* After emtying FIFO in status mode, turn off status mode */ if(sGetRxCnt(cp) == 0) { sDisRxStatusMode(cp); } } else { /* * Avoid the grotesquely inefficient lineswitch routine * (ttyinput) in "raw" mode. It usually takes about 450 * instructions (that's without canonical processing or echo!). * slinput is reasonably fast (usually 40 instructions plus * call overhead). */ ToRecv = sGetRxCnt(cp); if ( tp->t_state & TS_CAN_BYPASS_L_RINT ) { if ( ToRecv > RXFIFO_SIZE ) { ToRecv = RXFIFO_SIZE; } wRecv = ToRecv >> 1; if ( wRecv ) { rp_readmultich2(cp,sGetTxRxDataIO(cp),(u_int16_t *)rp->RxBuf,wRecv); } if ( ToRecv & 1 ) { ((unsigned char *)rp->RxBuf)[(ToRecv-1)] = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp)); } tk_nin += ToRecv; tk_rawcc += ToRecv; tp->t_rawcc += ToRecv; ttynocopy = b_to_q((char *)rp->RxBuf, ToRecv, &tp->t_rawq); ttwakeup(tp); } else { while (ToRecv) { if(tp->t_state & TS_TBLOCK) { break; } ch = (u_char) rp_readch1(cp,sGetTxRxDataIO(cp)); crit_enter(); (*linesw[tp->t_line].l_rint)(ch, tp); crit_exit(); ToRecv--; } } }
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; DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n")); if (in_intr) return; in_intr = 1; /* * 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; /* * See if a command has completed ? */ if (ccbp->hi_stat != pp->sp_pend) { DPRINT((pp, DBG_INTR, "si_intr hi_stat = 0x%x, pend = %d\n", ccbp->hi_stat, pp->sp_pend)); switch(pp->sp_pend) { case LOPEN: case MPEND: case MOPEN: case CONFIG: case SBREAK: case EBREAK: pp->sp_pend = ccbp->hi_stat; /* sleeping in si_command */ wakeup(&pp->sp_state); break; default: pp->sp_pend = ccbp->hi_stat; } } /* * Continue on if it's closed */ if (ccbp->hi_stat == IDLE_CLOSE) { 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. */ if (tp->t_state & TS_CONNECTED && tp->t_state & TS_ISOPEN) isopen = 1; else isopen = 0; /* * Do input break processing */ if (ccbp->hi_state & ST_BREAK) { if (isopen) { ttyld_rint(tp, TTY_BI); } 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: /* XXX Sorry. the nesting was driving me bats! :-( */ if (!isopen) { ccbp->hi_rxopos = ccbp->hi_rxipos; goto end_rx; } /* * 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; } /* * 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) { DPRINT((pp, DBG_INTR, "\tsingle copy\n")); z = ccbp->hi_rxbuf + op; si_vbcopy(z, si_rxbuf, n); op += n; } else { x = SI_BUFFERSIZE - op; DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x)); z = ccbp->hi_rxbuf + op; si_vbcopy(z, si_rxbuf, x); DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n", n - x)); z = ccbp->hi_rxbuf; si_vbcopy(z, si_rxbuf + x, n - x); op += n; } /* clear collected characters from buffer */ ccbp->hi_rxopos = op; DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n", n, op, ip)); /* * at this point... * n = number of chars placed in si_rxbuf */ /* * Avoid the grotesquely inefficient lineswitch * routine (ttyinput) in "raw" mode. It usually * takes about 450 instructions (that's without * canonical processing or echo!). slinput is * reasonably fast (usually 40 instructions * plus call overhead). */ if (tp->t_state & TS_CAN_BYPASS_L_RINT) { /* block if the driver supports it */ if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER && (tp->t_cflag & CRTS_IFLOW || tp->t_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK)) ttyblock(tp); tk_nin += n; tk_rawcc += n; tp->t_rawcc += n; pp->sp_delta_overflows += b_to_q((char *)si_rxbuf, n, &tp->t_rawq); ttwakeup(tp); if (tp->t_state & TS_TTSTOP && (tp->t_iflag & IXANY || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) { tp->t_state &= ~TS_TTSTOP; tp->t_lflag &= ~FLUSHO; si_start(tp); } } 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 (ttyld_rint(tp, i) == -1) { pp->sp_delta_overflows++; } } } goto more_rx; /* try for more until RXbuf is empty */ end_rx: /* XXX: Again, sorry about the gotos.. :-) */ /* * Do TX stuff */ ttyld_start(tp); } /* end of for (all ports on this controller) */ } /* end of for (all controllers) */ in_intr = 0; DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n")); }