Author: hselasky
Date: Mon Nov  5 17:50:40 2012
New Revision: 242619
URL: http://svnweb.freebsd.org/changeset/base/242619

Log:
  Add a jitter buffer in the common USB serial driver code which
  temporarily stores characters if the TTY buffer is full when
  used a as a console. This can happen when a console is suspended.
  Also properly do the flow stop signalling when this happens and
  flow start when the condition changes back to normal again.
  
  Bump __FreeBSD_version to force external kernel modules
  to be recompiled. No kernel API changes.
  
  MFC after:    1 week
  Suggested by: ed @

Modified:
  head/sys/dev/usb/serial/usb_serial.c
  head/sys/dev/usb/serial/usb_serial.h
  head/sys/sys/param.h

Modified: head/sys/dev/usb/serial/usb_serial.c
==============================================================================
--- head/sys/dev/usb/serial/usb_serial.c        Mon Nov  5 17:42:50 2012        
(r242618)
+++ head/sys/dev/usb/serial/usb_serial.c        Mon Nov  5 17:50:40 2012        
(r242619)
@@ -162,6 +162,7 @@ static tsw_ioctl_t ucom_ioctl;
 static tsw_modem_t ucom_modem;
 static tsw_param_t ucom_param;
 static tsw_outwakeup_t ucom_outwakeup;
+static tsw_inwakeup_t ucom_inwakeup;
 static tsw_free_t ucom_free;
 
 static struct ttydevsw ucom_class = {
@@ -169,6 +170,7 @@ static struct ttydevsw ucom_class = {
        .tsw_open = ucom_open,
        .tsw_close = ucom_close,
        .tsw_outwakeup = ucom_outwakeup,
+       .tsw_inwakeup = ucom_inwakeup,
        .tsw_ioctl = ucom_ioctl,
        .tsw_param = ucom_param,
        .tsw_modem = ucom_modem,
@@ -716,6 +718,10 @@ ucom_open(struct tty *tp)
        sc->sc_pls_set = 0;
        sc->sc_pls_clr = 0;
 
+       /* reset jitter buffer */
+       sc->sc_jitterbuf_in = 0;
+       sc->sc_jitterbuf_out = 0;
+
        ucom_queue_command(sc, ucom_cfg_open, NULL,
            &sc->sc_open_task[0].hdr,
            &sc->sc_open_task[1].hdr);
@@ -780,6 +786,47 @@ ucom_close(struct tty *tp)
        }
 }
 
+static void
+ucom_inwakeup(struct tty *tp)
+{
+       struct ucom_softc *sc = tty_softc(tp);
+       uint16_t pos;
+
+       if (sc == NULL)
+               return;
+
+       tty_lock(tp);
+
+       if (ttydisc_can_bypass(tp) != 0 || 
+           (sc->sc_flag & UCOM_FLAG_HL_READY) == 0) {
+               tty_unlock(tp);
+               return;
+       }
+
+       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);
+
+       tty_unlock(tp);
+}
+
 static int
 ucom_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
 {
@@ -1360,6 +1407,11 @@ ucom_put_data(struct ucom_softc *sc, str
                /* 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);
                        }
@@ -1368,8 +1420,31 @@ ucom_put_data(struct ucom_softc *sc, str
                /* need to loop */
 
                for (cnt = 0; cnt != res.length; cnt++) {
-                       if (ttydisc_rint(tp, buf[cnt], 0) == -1) {
-                               /* XXX what should we do? */
+                       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);

Modified: head/sys/dev/usb/serial/usb_serial.h
==============================================================================
--- head/sys/dev/usb/serial/usb_serial.h        Mon Nov  5 17:42:50 2012        
(r242618)
+++ head/sys/dev/usb/serial/usb_serial.h        Mon Nov  5 17:50:40 2012        
(r242619)
@@ -78,6 +78,7 @@
 #define        UCOM_MINVER     1
 #define        UCOM_PREFVER    UCOM_MODVER
 #define        UCOM_MAXVER     1
+#define        UCOM_JITTERBUF_SIZE     128     /* bytes */
 
 struct usb_device;
 struct ucom_softc;
@@ -169,6 +170,8 @@ struct ucom_softc {
        struct mtx *sc_mtx;
        void   *sc_parent;
        int sc_subunit;
+       uint16_t sc_jitterbuf_in;
+       uint16_t sc_jitterbuf_out;
        uint16_t sc_portno;
        uint16_t sc_flag;
 #define        UCOM_FLAG_RTS_IFLOW     0x01    /* use RTS input flow control */
@@ -191,6 +194,7 @@ struct ucom_softc {
 #define        UCOM_LS_RTS     0x02
 #define        UCOM_LS_BREAK   0x04
 #define        UCOM_LS_RING    0x08
+       uint8_t sc_jitterbuf[UCOM_JITTERBUF_SIZE];
 };
 
 #define        UCOM_MTX_ASSERT(sc, what) mtx_assert((sc)->sc_mtx, what)

Modified: head/sys/sys/param.h
==============================================================================
--- head/sys/sys/param.h        Mon Nov  5 17:42:50 2012        (r242618)
+++ head/sys/sys/param.h        Mon Nov  5 17:50:40 2012        (r242619)
@@ -58,7 +58,7 @@
  *             in the range 5 to 9.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 1000022      /* Master, propagated to newvers */
+#define __FreeBSD_version 1000023      /* Master, propagated to newvers */
 
 /*
  * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to