static void zsttystart(struct tty *tp) { struct zstty_softc *sc; uint8_t c; sc = tp->t_dev->si_drv1; if ((tp->t_state & TS_TBLOCK) != 0) /* XXX clear RTS */; else /* XXX set RTS */; if ((tp->t_state & (TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) != 0) { ttwwakeup(tp); return; } if (tp->t_outq.c_cc <= tp->t_olowat) { if ((tp->t_state & TS_SO_OLOWAT) != 0) { tp->t_state &= ~TS_SO_OLOWAT; wakeup(TSA_OLOWAT(tp)); } selwakeup(&tp->t_wsel); if (tp->t_outq.c_cc == 0) { if ((tp->t_state & (TS_BUSY | TS_SO_OCOMPLETE)) == TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { tp->t_state &= ~TS_SO_OCOMPLETE; wakeup(TSA_OCOMPLETE(tp)); } return; } } sc->sc_ocnt = q_to_b(&tp->t_outq, sc->sc_obuf, sizeof(sc->sc_obuf)); if (sc->sc_ocnt == 0) return; c = sc->sc_obuf[0]; sc->sc_oget = sc->sc_obuf + 1; sc->sc_ocnt--; tp->t_state |= TS_BUSY; sc->sc_tx_busy = 1; /* * Enable transmit interrupts if necessary and send the first * character to start up the transmitter. */ if ((sc->sc_preg[1] & ZSWR1_TIE) == 0) { sc->sc_preg[1] |= ZSWR1_TIE; sc->sc_creg[1] = sc->sc_preg[1]; ZS_WRITE_REG(sc, 1, sc->sc_creg[1]); } ZS_WRITE(sc, sc->sc_data, c); ttwwakeup(tp); }
/* * Stop output on a line. called at spltty(); */ static void si_stop(struct tty *tp, int rw) { volatile struct si_channel *ccbp; struct si_port *pp; mtx_assert(&Giant, MA_OWNED); pp = tty_softc(tp); ccbp = pp->sp_ccb; DPRINT((pp, DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw)); /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */ if (rw & FWRITE) { /* what level are we meant to be flushing anyway? */ if (tp->t_state & TS_BUSY) { si_command(pp, WFLUSH, SI_NOWAIT); tp->t_state &= ~TS_BUSY; ttwwakeup(tp); /* Bruce???? */ } } #if 1 /* XXX: this doesn't work right yet.. */ /* XXX: this may have been failing because we used to call l_rint() * while we were looping based on these two counters. Now, we collect * the data and then loop stuffing it into l_rint(), making this * useless. Should we cause this to blow away the staging buffer? */ if (rw & FREAD) { ccbp->hi_rxopos = ccbp->hi_rxipos; } #endif }
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); }
static int kmoutput( struct tty *tp) { /* * FIXME - to be grokked...copied from m68k km.c. */ char buf[80]; char *cp; int cc = -1; extern int hz; while (tp->t_outq.c_cc > 0) { cc = ndqb(&tp->t_outq, 0); if (cc == 0) break; cc = min(cc, sizeof buf); (void) q_to_b(&tp->t_outq, buf, cc); for (cp = buf; cp < &buf[cc]; cp++) { kmputc(*cp & 0x7f); } } if (tp->t_outq.c_cc > 0) { timeout((timeout_fcn_t)kmtimeout, tp, hz); } tp->t_state &= ~TS_BUSY; ttwwakeup(tp); return 0; }
static void kmstart( struct tty *tp) { extern int hz; if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) goto out; if (tp->t_outq.c_cc == 0) goto out; tp->t_state |= TS_BUSY; if (tp->t_outq.c_cc > tp->t_lowat) { /* * Start immediately. */ kmoutput(tp); } else { /* * Wait a bit... */ #if 0 /* FIXME */ timeout(kmtimeout, tp, hz); #else kmoutput(tp); #endif } out: ttwwakeup(tp); }
/* * Note: called at splsoftclock from the timeout code * This has to deal with two things... cause wakeups while waiting for * tty drains on last process exit, and call l_start at about the right * time for protocols like ppp. */ static void si_lstart(void *arg) { struct si_port *pp = arg; struct tty *tp; int oldspl; DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n", pp, pp->sp_state)); oldspl = spltty(); tp = pp->sp_tty; if ((tp->t_state & TS_ISOPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) { splx(oldspl); return; } pp->sp_state &= ~SS_LSTART; pp->sp_state |= SS_INLSTART; /* deal with the process exit case */ ttwwakeup(tp); /* nudge protocols - eg: ppp */ ttyld_start(tp); pp->sp_state &= ~SS_INLSTART; splx(oldspl); }
static void ofw_tty_start(struct tty *tp) { if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { ttwwakeup(tp); return; } tp->t_state |= TS_BUSY; while (tp->t_outq.c_cc != 0) { ofw_cons_putc(tp->t_dev, getc(&tp->t_outq)); } tp->t_state &= ~TS_BUSY; ttwwakeup(tp); }
static void dcons_tty_start(struct tty *tp) { struct dcons_softc *dc; int s; dc = (struct dcons_softc *)tp->t_dev->si_drv1; s = spltty(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { ttwwakeup(tp); return; } tp->t_state |= TS_BUSY; while (tp->t_outq.c_cc != 0) dcons_putc(dc, getc(&tp->t_outq)); tp->t_state &= ~TS_BUSY; ttwwakeup(tp); splx(s); }
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 int ptcread(struct dev_read_args *ap) { cdev_t dev = ap->a_head.a_dev; struct tty *tp = dev->si_tty; struct pt_ioctl *pti = dev->si_drv1; char buf[BUFSIZ]; int error = 0, cc; lwkt_gettoken(&tty_token); /* * We want to block until the slave * is open, and there's something to read; * but if we lost the slave or we're NBIO, * then return the appropriate error instead. */ for (;;) { if (tp->t_state&TS_ISOPEN) { if ((pti->pt_flags & PF_PKT) && pti->pt_send) { error = ureadc((int)pti->pt_send, ap->a_uio); if (error) { lwkt_reltoken(&tty_token); return (error); } if (pti->pt_send & TIOCPKT_IOCTL) { cc = (int)szmin(ap->a_uio->uio_resid, sizeof(tp->t_termios)); uiomove((caddr_t)&tp->t_termios, cc, ap->a_uio); } pti->pt_send = 0; lwkt_reltoken(&tty_token); return (0); } if ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl) { error = ureadc((int)pti->pt_ucntl, ap->a_uio); if (error) { lwkt_reltoken(&tty_token); return (error); } pti->pt_ucntl = 0; lwkt_reltoken(&tty_token); return (0); } if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) break; } if ((tp->t_state & TS_CONNECTED) == 0) { lwkt_reltoken(&tty_token); return (0); /* EOF */ } if (ap->a_ioflag & IO_NDELAY) { lwkt_reltoken(&tty_token); return (EWOULDBLOCK); } error = tsleep(TSA_PTC_READ(tp), PCATCH, "ptcin", 0); if (error) { lwkt_reltoken(&tty_token); return (error); } } if (pti->pt_flags & (PF_PKT|PF_UCNTL)) error = ureadc(0, ap->a_uio); while (ap->a_uio->uio_resid > 0 && error == 0) { cc = q_to_b(&tp->t_outq, buf, (int)szmin(ap->a_uio->uio_resid, BUFSIZ)); if (cc <= 0) break; error = uiomove(buf, (size_t)cc, ap->a_uio); } ttwwakeup(tp); lwkt_reltoken(&tty_token); return (error); }
Static void ucomstart(struct tty *tp) { struct ucom_softc *sc; struct cblock *cbp; usbd_status err; int s; u_char *data; int cnt; USB_GET_SC(ucom, UCOMUNIT(tp->t_dev), sc); DPRINTF(("ucomstart: sc = %p\n", sc)); if (sc->sc_dying) return; s = spltty(); if (tp->t_state & TS_TBLOCK) { if (ISSET(sc->sc_mcr, UMCR_RTS) && ISSET(sc->sc_state, UCS_RTS_IFLOW)) { DPRINTF(("ucomstart: clear RTS\n")); (void)ucomctl(sc, UMCR_RTS, DMBIC); } } else { if (!ISSET(sc->sc_mcr, UMCR_RTS) && tp->t_rawq.c_cc <= tp->t_ilowat && ISSET(sc->sc_state, UCS_RTS_IFLOW)) { DPRINTF(("ucomstart: set RTS\n")); (void)ucomctl(sc, UMCR_RTS, DMBIS); } } if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) { ttwwakeup(tp); DPRINTF(("ucomstart: stopped\n")); goto out; } if (tp->t_outq.c_cc <= tp->t_olowat) { if (ISSET(tp->t_state, TS_SO_OLOWAT)) { CLR(tp->t_state, TS_SO_OLOWAT); wakeup(TSA_OLOWAT(tp)); } selwakeup(&tp->t_wsel); if (tp->t_outq.c_cc == 0) { if (ISSET(tp->t_state, TS_BUSY | TS_SO_OCOMPLETE) == TS_SO_OCOMPLETE && tp->t_outq.c_cc == 0) { CLR(tp->t_state, TS_SO_OCOMPLETE); wakeup(TSA_OCOMPLETE(tp)); } goto out; } } /* Grab the first contiguous region of buffer space. */ data = tp->t_outq.c_cf; cbp = (struct cblock *) ((intptr_t) tp->t_outq.c_cf & ~CROUND); cnt = min((char *) (cbp+1) - tp->t_outq.c_cf, tp->t_outq.c_cc); if (cnt == 0) { DPRINTF(("ucomstart: cnt == 0\n")); goto out; } SET(tp->t_state, TS_BUSY); if (cnt > sc->sc_obufsize) { DPRINTF(("ucomstart: big buffer %d chars\n", cnt)); cnt = sc->sc_obufsize; } if (sc->sc_callback->ucom_write != NULL) sc->sc_callback->ucom_write(sc->sc_parent, sc->sc_portno, sc->sc_obuf, data, &cnt); else memcpy(sc->sc_obuf, data, cnt); DPRINTF(("ucomstart: %d chars\n", cnt)); usbd_setup_xfer(sc->sc_oxfer, sc->sc_bulkout_pipe, (usbd_private_handle)sc, sc->sc_obuf, cnt, USBD_NO_COPY, USBD_NO_TIMEOUT, ucomwritecb); /* What can we do on error? */ err = usbd_transfer(sc->sc_oxfer); if (err != USBD_IN_PROGRESS) printf("ucomstart: err=%s\n", usbd_errstr(err)); ttwwakeup(tp); out: splx(s); }
/* * Nudge the transmitter... * * XXX: I inherited some funny code here. It implies the host card only * interrupts when the transmit buffer reaches the low-water-mark, and does * not interrupt when it's actually hits empty. In some cases, we have * processes waiting for complete drain, and we need to simulate an interrupt * about when we think the buffer is going to be empty (and retry if not). * I really am not certain about this... I *need* the hardware manuals. */ static void si_start(struct tty *tp) { struct si_port *pp; volatile struct si_channel *ccbp; struct clist *qp; BYTE ipos; int nchar; int oldspl, count, n, amount, buffer_full; oldspl = spltty(); qp = &tp->t_outq; pp = tp->t_sc; DPRINT((pp, DBG_ENTRY|DBG_START, "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n", tp, tp->t_state, pp->sp_state, qp->c_cc)); if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) goto out; buffer_full = 0; ccbp = pp->sp_ccb; count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; DPRINT((pp, DBG_START, "count %d\n", (BYTE)count)); while ((nchar = qp->c_cc) > 0) { if ((BYTE)count >= 255) { buffer_full++; break; } amount = min(nchar, (255 - (BYTE)count)); ipos = (unsigned int)ccbp->hi_txipos; n = q_to_b(&tp->t_outq, si_txbuf, amount); /* will it fit in one lump? */ if ((SI_BUFFERSIZE - ipos) >= n) { si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n); } else { si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], SI_BUFFERSIZE - ipos); si_bcopyv(si_txbuf + (SI_BUFFERSIZE - ipos), &ccbp->hi_txbuf[0], n - (SI_BUFFERSIZE - ipos)); } ccbp->hi_txipos += n; count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos; } if (count != 0 && nchar == 0) { tp->t_state |= TS_BUSY; } else { tp->t_state &= ~TS_BUSY; } /* wakeup time? */ ttwwakeup(tp); DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n", (BYTE)count, nchar, tp->t_state)); if (tp->t_state & TS_BUSY) { int time; time = ttspeedtab(tp->t_ospeed, chartimes); if (time > 0) { if (time < nchar) time = nchar / time; else time = 2; } else { DPRINT((pp, DBG_START, "bad char time value! %d\n", time)); time = hz/10; } if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) { untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch); } else { pp->sp_state |= SS_LSTART; } DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time)); pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time); } out: splx(oldspl); DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n")); }