static void tiocm_to_ucom(struct ucom_softc *sc, u_long how, int ttybits) { u_char combits; combits = 0; if (ISSET(ttybits, TIOCM_DTR)) SET(combits, UMCR_DTR); if (ISSET(ttybits, TIOCM_RTS)) SET(combits, UMCR_RTS); switch (how) { case TIOCMBIC: CLR(sc->sc_mcr, combits); break; case TIOCMBIS: SET(sc->sc_mcr, combits); break; case TIOCMSET: CLR(sc->sc_mcr, UMCR_DTR | UMCR_RTS); SET(sc->sc_mcr, combits); break; } if (how == TIOCMSET || ISSET(combits, UMCR_DTR)) ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0); if (how == TIOCMSET || ISSET(combits, UMCR_RTS)) ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0); }
static int ucom_modem(struct tty *tp, int sigon, int sigoff) { struct ucom_softc *sc; uint8_t onoff; sc = devclass_get_softc(ucom_devclass, minor(tp->t_dev)); UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return (0); } if ((sigon == 0) && (sigoff == 0)) { if (sc->sc_mcr & SER_DTR) { sigon |= SER_DTR; } if (sc->sc_mcr & SER_RTS) { sigon |= SER_RTS; } if (sc->sc_msr & SER_CTS) { sigon |= SER_CTS; } if (sc->sc_msr & SER_DCD) { sigon |= SER_DCD; } if (sc->sc_msr & SER_DSR) { sigon |= SER_DSR; } if (sc->sc_msr & SER_RI) { sigon |= SER_RI; } return (sigon); } if (sigon & SER_DTR) { sc->sc_mcr |= SER_DTR; } if (sigoff & SER_DTR) { sc->sc_mcr &= ~SER_DTR; } if (sigon & SER_RTS) { sc->sc_mcr |= SER_RTS; } if (sigoff & SER_RTS) { sc->sc_mcr &= ~SER_RTS; } onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0; ucom_dtr(sc, onoff); onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0; ucom_rts(sc, onoff); return (0); }
static int ucom_modem(struct tty *tp, int sigon, int sigoff) { struct ucom_softc *sc = tty_softc(tp); uint8_t onoff; mtx_assert(sc->sc_mtx, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { return (0); } if ((sigon == 0) && (sigoff == 0)) { if (sc->sc_mcr & SER_DTR) { sigon |= SER_DTR; } if (sc->sc_mcr & SER_RTS) { sigon |= SER_RTS; } if (sc->sc_msr & SER_CTS) { sigon |= SER_CTS; } if (sc->sc_msr & SER_DCD) { sigon |= SER_DCD; } if (sc->sc_msr & SER_DSR) { sigon |= SER_DSR; } if (sc->sc_msr & SER_RI) { sigon |= SER_RI; } return (sigon); } if (sigon & SER_DTR) { sc->sc_mcr |= SER_DTR; } if (sigoff & SER_DTR) { sc->sc_mcr &= ~SER_DTR; } if (sigon & SER_RTS) { sc->sc_mcr |= SER_RTS; } if (sigoff & SER_RTS) { sc->sc_mcr &= ~SER_RTS; } onoff = (sc->sc_mcr & SER_DTR) ? 1 : 0; ucom_dtr(sc, onoff); onoff = (sc->sc_mcr & SER_RTS) ? 1 : 0; ucom_rts(sc, onoff); return (0); }
void ucom_dtr(struct ucom_softc *sc, int onoff) { DPRINTF(("ucom_dtr: onoff=%d\n", onoff)); if (sc->sc_methods->ucom_set != NULL) { sc->sc_methods->ucom_set(sc->sc_parent, sc->sc_portno, UCOM_SET_DTR, onoff); /* When not using CRTSCTS, RTS follows DTR. */ if (!(sc->sc_swflags & TIOCFLAG_CRTSCTS)) ucom_rts(sc, onoff); } }
static void ucom_inwakeup(struct tty *tp) { struct ucom_softc *sc = tty_softc(tp); uint16_t pos; if (sc == NULL) return; UCOM_MTX_ASSERT(sc, MA_OWNED); DPRINTF("tp=%p\n", tp); if (ttydisc_can_bypass(tp) != 0 || (sc->sc_flag & UCOM_FLAG_HL_READY) == 0 || (sc->sc_flag & UCOM_FLAG_INWAKEUP) != 0) { return; } /* prevent recursion */ sc->sc_flag |= UCOM_FLAG_INWAKEUP; pos = sc->sc_jitterbuf_out; while (sc->sc_jitterbuf_in != pos) { int c; c = (char)sc->sc_jitterbuf[pos]; if (ttydisc_rint(tp, c, 0) == -1) break; pos++; if (pos >= UCOM_JITTERBUF_SIZE) pos -= UCOM_JITTERBUF_SIZE; } sc->sc_jitterbuf_out = pos; /* clear RTS in async fashion */ if ((sc->sc_jitterbuf_in == pos) && (sc->sc_flag & UCOM_FLAG_RTS_IFLOW)) ucom_rts(sc, 0); sc->sc_flag &= ~UCOM_FLAG_INWAKEUP; }
int ucomopen(dev_t dev, int flag, int mode, struct lwp *l) { int unit = UCOMUNIT(dev); usbd_status err; struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit); struct ucom_buffer *ub; struct tty *tp; int s, i; int error; if (sc == NULL) return (ENXIO); if (sc->sc_dying) return (EIO); if (!device_is_active(sc->sc_dev)) return (ENXIO); tp = sc->sc_tty; DPRINTF(("ucomopen: unit=%d, tp=%p\n", unit, tp)); if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) return (EBUSY); s = spltty(); /* * Do the following iff this is a first open. */ while (sc->sc_opening) tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0); if (sc->sc_dying) { splx(s); return (EIO); } sc->sc_opening = 1; if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { struct termios t; tp->t_dev = dev; if (sc->sc_methods->ucom_open != NULL) { error = sc->sc_methods->ucom_open(sc->sc_parent, sc->sc_portno); if (error) { ucom_cleanup(sc); sc->sc_opening = 0; wakeup(&sc->sc_opening); splx(s); return (error); } } ucom_status_change(sc); /* * Initialize the termios status to the defaults. Add in the * sticky bits from TIOCSFLAGS. */ t.c_ispeed = 0; t.c_ospeed = TTYDEF_SPEED; t.c_cflag = TTYDEF_CFLAG; if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL)) SET(t.c_cflag, CLOCAL); if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) SET(t.c_cflag, CRTSCTS); if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF)) SET(t.c_cflag, MDMBUF); /* Make sure ucomparam() will do something. */ tp->t_ospeed = 0; (void) ucomparam(tp, &t); tp->t_iflag = TTYDEF_IFLAG; tp->t_oflag = TTYDEF_OFLAG; tp->t_lflag = TTYDEF_LFLAG; ttychars(tp); ttsetwater(tp); /* * Turn on DTR. We must always do this, 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. Ditto RTS. */ ucom_dtr(sc, 1); ucom_rts(sc, 1); DPRINTF(("ucomopen: open pipes in=%d out=%d\n", sc->sc_bulkin_no, sc->sc_bulkout_no)); /* Open the bulk pipes */ err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkin_no, USBD_EXCLUSIVE_USE, &sc->sc_bulkin_pipe); if (err) { DPRINTF(("%s: open bulk in error (addr %d), err=%s\n", USBDEVNAME(sc->sc_dev), sc->sc_bulkin_no, usbd_errstr(err))); error = EIO; goto fail_0; } err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no, USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe); if (err) { DPRINTF(("%s: open bulk out error (addr %d), err=%s\n", USBDEVNAME(sc->sc_dev), sc->sc_bulkout_no, usbd_errstr(err))); error = EIO; goto fail_1; } sc->sc_rx_unblock = 0; sc->sc_rx_stopped = 0; sc->sc_tx_stopped = 0; memset(sc->sc_ibuff, 0, sizeof(sc->sc_ibuff)); memset(sc->sc_obuff, 0, sizeof(sc->sc_obuff)); SIMPLEQ_INIT(&sc->sc_ibuff_empty); SIMPLEQ_INIT(&sc->sc_ibuff_full); SIMPLEQ_INIT(&sc->sc_obuff_free); SIMPLEQ_INIT(&sc->sc_obuff_full); /* Allocate input buffers */ for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS]; ub++) { ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev); if (ub->ub_xfer == NULL) { error = ENOMEM; goto fail_2; } ub->ub_data = usbd_alloc_buffer(ub->ub_xfer, sc->sc_ibufsizepad); if (ub->ub_data == NULL) { error = ENOMEM; goto fail_2; } if (ucomsubmitread(sc, ub) != USBD_NORMAL_COMPLETION) { error = EIO; goto fail_2; } } for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS]; ub++) { ub->ub_xfer = usbd_alloc_xfer(sc->sc_udev); if (ub->ub_xfer == NULL) { error = ENOMEM; goto fail_2; } ub->ub_data = usbd_alloc_buffer(ub->ub_xfer, sc->sc_obufsize); if (ub->ub_data == NULL) { error = ENOMEM; goto fail_2; } SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link); } } sc->sc_opening = 0; wakeup(&sc->sc_opening); splx(s); error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK)); if (error) goto bad; error = (*tp->t_linesw->l_open)(dev, tp); if (error) goto bad; return (0); fail_2: usbd_abort_pipe(sc->sc_bulkin_pipe); for (i = 0; i < UCOM_IN_BUFFS; i++) { if (sc->sc_ibuff[i].ub_xfer != NULL) { usbd_free_xfer(sc->sc_ibuff[i].ub_xfer); sc->sc_ibuff[i].ub_xfer = NULL; sc->sc_ibuff[i].ub_data = NULL; } } usbd_abort_pipe(sc->sc_bulkout_pipe); for (i = 0; i < UCOM_OUT_BUFFS; i++) { if (sc->sc_obuff[i].ub_xfer != NULL) { usbd_free_xfer(sc->sc_obuff[i].ub_xfer); sc->sc_obuff[i].ub_xfer = NULL; sc->sc_obuff[i].ub_data = NULL; } } usbd_close_pipe(sc->sc_bulkout_pipe); sc->sc_bulkout_pipe = NULL; fail_1: usbd_close_pipe(sc->sc_bulkin_pipe); sc->sc_bulkin_pipe = NULL; fail_0: sc->sc_opening = 0; wakeup(&sc->sc_opening); splx(s); return (error); bad: s = spltty(); CLR(tp->t_state, TS_BUSY); if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) { /* * We failed to open the device, and nobody else had it opened. * Clean up the state as appropriate. */ ucom_cleanup(sc); } splx(s); return (error); }
void ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len) { struct usb_page_search res; struct tty *tp = sc->sc_tty; char *buf; uint32_t cnt; UCOM_MTX_ASSERT(sc, MA_OWNED); if (sc->sc_flag & UCOM_FLAG_CONSOLE) { unsigned int temp; /* get maximum RX length */ temp = (UCOM_CONS_BUFSIZE - 1) - ucom_cons_rx_high + ucom_cons_rx_low; temp %= UCOM_CONS_BUFSIZE; /* limit RX length */ if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_rx_high)) temp = (UCOM_CONS_BUFSIZE - ucom_cons_rx_high); if (temp > len) temp = len; /* copy out data */ usbd_copy_out(pc, offset, ucom_cons_rx_buf + ucom_cons_rx_high, temp); /* update counters */ ucom_cons_rx_high += temp; ucom_cons_rx_high %= UCOM_CONS_BUFSIZE; return; } if (tty_gone(tp)) return; /* multiport device polling */ if (len == 0) return; /* no data */ /* set a flag to prevent recursation ? */ while (len > 0) { usbd_get_page(pc, offset, &res); if (res.length > len) { res.length = len; } len -= res.length; offset += res.length; /* pass characters to tty layer */ buf = res.buffer; cnt = res.length; /* first check if we can pass the buffer directly */ if (ttydisc_can_bypass(tp)) { /* clear any jitter buffer */ sc->sc_jitterbuf_in = 0; sc->sc_jitterbuf_out = 0; if (ttydisc_rint_bypass(tp, buf, cnt) != cnt) { DPRINTF("tp=%p, data lost\n", tp); } continue; } /* need to loop */ for (cnt = 0; cnt != res.length; cnt++) { if (sc->sc_jitterbuf_in != sc->sc_jitterbuf_out || ttydisc_rint(tp, buf[cnt], 0) == -1) { uint16_t end; uint16_t pos; pos = sc->sc_jitterbuf_in; end = sc->sc_jitterbuf_out + UCOM_JITTERBUF_SIZE - 1; if (end >= UCOM_JITTERBUF_SIZE) end -= UCOM_JITTERBUF_SIZE; for (; cnt != res.length; cnt++) { if (pos == end) break; sc->sc_jitterbuf[pos] = buf[cnt]; pos++; if (pos >= UCOM_JITTERBUF_SIZE) pos -= UCOM_JITTERBUF_SIZE; } sc->sc_jitterbuf_in = pos; /* set RTS in async fashion */ if (sc->sc_flag & UCOM_FLAG_RTS_IFLOW) ucom_rts(sc, 1); DPRINTF("tp=%p, lost %d " "chars\n", tp, res.length - cnt); break; } } } ttydisc_rint_done(tp); }
Static int ucomctl(struct ucom_softc *sc, int bits, int how) { int mcr; int msr; int onoff; DPRINTF(("ucomctl: bits = 0x%x, how = %d\n", bits, how)); if (how == DMGET) { SET(bits, TIOCM_LE); /* always set TIOCM_LE bit */ DPRINTF(("ucomctl: DMGET: LE")); mcr = sc->sc_mcr; if (ISSET(mcr, UMCR_DTR)) { SET(bits, TIOCM_DTR); DPRINTF((" DTR")); } if (ISSET(mcr, UMCR_RTS)) { SET(bits, TIOCM_RTS); DPRINTF((" RTS")); } msr = sc->sc_msr; if (ISSET(msr, UMSR_CTS)) { SET(bits, TIOCM_CTS); DPRINTF((" CTS")); } if (ISSET(msr, UMSR_DCD)) { SET(bits, TIOCM_CD); DPRINTF((" CD")); } if (ISSET(msr, UMSR_DSR)) { SET(bits, TIOCM_DSR); DPRINTF((" DSR")); } if (ISSET(msr, UMSR_RI)) { SET(bits, TIOCM_RI); DPRINTF((" RI")); } DPRINTF(("\n")); return (bits); } mcr = 0; if (ISSET(bits, TIOCM_DTR)) SET(mcr, UMCR_DTR); if (ISSET(bits, TIOCM_RTS)) SET(mcr, UMCR_RTS); switch (how) { case DMSET: sc->sc_mcr = mcr; break; case DMBIS: sc->sc_mcr |= mcr; break; case DMBIC: sc->sc_mcr &= ~mcr; break; } onoff = ISSET(sc->sc_mcr, UMCR_DTR) ? 1 : 0; ucom_dtr(sc, onoff); onoff = ISSET(sc->sc_mcr, UMCR_RTS) ? 1 : 0; ucom_rts(sc, onoff); return (0); }