Index: sys/dev/usb/ucom.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/ucom.c,v retrieving revision 1.108.2.31 diff -u -p -r1.108.2.31 ucom.c --- sys/dev/usb/ucom.c 6 Nov 2016 11:50:54 -0000 1.108.2.31 +++ sys/dev/usb/ucom.c 15 Nov 2016 20:56:44 -0000 @@ -1523,6 +1523,8 @@ ucom_read_complete(struct ucom_softc *sc if (ub->ub_index == ub->ub_len) { SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_full, ub_link); + sc->sc_refcnt--; + /* increments sc_refcnt */ ucomsubmitread(sc, ub); ub = SIMPLEQ_FIRST(&sc->sc_ibuff_full); @@ -1537,6 +1539,8 @@ ucomsubmitread(struct ucom_softc *sc, st { usbd_status err; + KASSERT(mutex_owned(&sc->sc_lock)); + if (sc->sc_bulkin_no != -1) { usbd_setup_xfer(ub->ub_xfer, sc, ub->ub_data, sc->sc_ibufsize, USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, ucomreadcb); @@ -1548,6 +1552,8 @@ ucomsubmitread(struct ucom_softc *sc, st } } + sc->sc_refcnt++; + SIMPLEQ_INSERT_TAIL(&sc->sc_ibuff_empty, ub, ub_link); return 0; @@ -1557,19 +1563,21 @@ 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; struct ucom_buffer *ub; uint32_t cc; u_char *cp; UCOMHIST_FUNC(); UCOMHIST_CALLED(); + mutex_enter(&sc->sc_lock); + if (status == USBD_CANCELLED) { DPRINTF("... done (cancelled status %d)", status, 0, 0, 0); - return; + goto out; } - mutex_enter(&sc->sc_lock); + struct tty *tp = sc->sc_tty; + if (status == USBD_IOERROR || sc->sc_dying) { DPRINTF("dying", 0, 0, 0, 0); /* Send something to wake upper layer */ @@ -1577,8 +1585,7 @@ ucomreadcb(struct usbd_xfer *xfer, void mutex_spin_enter(&tty_lock); /* XXX */ ttwakeup(tp); mutex_spin_exit(&tty_lock); /* XXX */ - mutex_exit(&sc->sc_lock); - return; + goto out; } ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty); @@ -1596,7 +1603,8 @@ ucomreadcb(struct usbd_xfer *xfer, void } DPRINTF("... done (status %d)", status, 0, 0, 0); - /* re-adds ub to sc_ibuff_empty */ + sc->sc_refcnt--; + /* re-adds ub to sc_ibuff_empty and increments sc_refcnt */ ucomsubmitread(sc, ub); mutex_exit(&sc->sc_lock); return; @@ -1613,16 +1621,18 @@ ucomreadcb(struct usbd_xfer *xfer, void KDASSERT(cp == ub->ub_data); - rnd_add_uint32(&sc->sc_rndsource, cc); - if (sc->sc_state != UCOM_OPEN) { /* Go around again - we're not quite ready */ + sc->sc_refcnt--; + /* re-adds ub to sc_ibuff_empty and increments sc_refcnt */ ucomsubmitread(sc, ub); mutex_exit(&sc->sc_lock); DPRINTF("... done (not open)", 0, 0, 0, 0); return; } + rnd_add_uint32(&sc->sc_rndsource, cc); + ub->ub_data = usbd_get_buffer(xfer); if (sc->sc_methods->ucom_read != NULL) { sc->sc_methods->ucom_read(sc->sc_parent, sc->sc_portno, @@ -1639,6 +1649,14 @@ ucomreadcb(struct usbd_xfer *xfer, void mutex_exit(&sc->sc_lock); DPRINTF("... done", 0, 0, 0, 0); + return; + +out: + if (--sc->sc_refcnt < 0) + cv_broadcast(&sc->sc_detachcv); + DPRINTF("unit=%d refcnt %d", UCOMUNIT(sc->sc_dev), sc->sc_refcnt, 0, 0); + mutex_exit(&sc->sc_lock); + } static void