Module Name: src
Committed By: skrll
Date: Sun Nov 6 11:50:54 UTC 2016
Modified Files:
src/sys/dev/usb [nick-nhusb]: ucom.c
Log Message:
Reduce the scope of the softc lock further and track device state via
sc_state.
All ucom methods apart from ucom_{read,write} are called without the
softc lock held.
ucom_close is called on last close only to match ucom_open being called
on first open only.
Fix ucom_detach where refcnt wasn't being decremented.
More DEBUG.
XXX still not sure where tty_lock needs to be held.
To generate a diff of this commit:
cvs rdiff -u -r1.108.2.30 -r1.108.2.31 src/sys/dev/usb/ucom.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/ucom.c
diff -u src/sys/dev/usb/ucom.c:1.108.2.30 src/sys/dev/usb/ucom.c:1.108.2.31
--- src/sys/dev/usb/ucom.c:1.108.2.30 Sun Nov 6 09:36:53 2016
+++ src/sys/dev/usb/ucom.c Sun Nov 6 11:50:54 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ucom.c,v 1.108.2.30 2016/11/06 09:36:53 skrll Exp $ */
+/* $NetBSD: ucom.c,v 1.108.2.31 2016/11/06 11:50:54 skrll Exp $ */
/*
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.108.2.30 2016/11/06 09:36:53 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.108.2.31 2016/11/06 11:50:54 skrll Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -78,7 +78,7 @@ __KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.1
#ifndef UCOM_DEBUG
#define ucomdebug 0
#else
-int ucomdebug = 0;
+int ucomdebug = 10;
SYSCTL_SETUP(sysctl_hw_ucom_setup, "sysctl hw.ucom setup")
{
@@ -181,8 +181,13 @@ struct ucom_softc {
u_char sc_tx_stopped;
int sc_swflags;
- u_char sc_opening; /* lock during open */
- u_char sc_closing; /* lock during close */
+ enum ucom_state {
+ UCOM_DEAD,
+ UCOM_ATTACHED,
+ UCOM_OPENING,
+ UCOM_CLOSING,
+ UCOM_OPEN
+ } sc_state;
int sc_refcnt;
bool sc_dying; /* disconnecting */
@@ -191,7 +196,7 @@ struct ucom_softc {
krndsource_t sc_rndsource; /* random source */
kmutex_t sc_lock;
- kcondvar_t sc_opencv;
+ kcondvar_t sc_statecv;
kcondvar_t sc_detachcv;
};
@@ -291,14 +296,13 @@ ucom_attach(device_t parent, device_t se
sc->sc_mcr = 0;
sc->sc_tx_stopped = 0;
sc->sc_swflags = 0;
- sc->sc_opening = 0;
- sc->sc_closing = 0;
sc->sc_refcnt = 0;
sc->sc_dying = false;
+ sc->sc_state = UCOM_DEAD;
sc->sc_si = softint_establish(SOFTINT_USB, ucom_softintr, sc);
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
- cv_init(&sc->sc_opencv, "ucomopen");
+ cv_init(&sc->sc_statecv, "ucomstate");
cv_init(&sc->sc_detachcv, "ucomdtch");
SIMPLEQ_INIT(&sc->sc_ibuff_empty);
@@ -384,6 +388,9 @@ ucom_attach(device_t parent, device_t se
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
+
+ sc->sc_state = UCOM_ATTACHED;
+
return;
fail_2:
@@ -434,6 +441,18 @@ ucom_detach(device_t self, int flags)
usbd_abort_pipe(sc->sc_bulkout_pipe);
mutex_enter(&sc->sc_lock);
+
+ /* wait for open/close to finish */
+ while (sc->sc_state == UCOM_OPENING || sc->sc_state == UCOM_CLOSING) {
+ int error = cv_wait_sig(&sc->sc_statecv, &sc->sc_lock);
+
+ if (error) {
+ mutex_exit(&sc->sc_lock);
+ return error;
+ }
+ }
+
+ sc->sc_refcnt--;
while (sc->sc_refcnt > 0) {
/* Wake up anyone waiting */
if (tp != NULL) {
@@ -494,7 +513,7 @@ ucom_detach(device_t self, int flags)
rnd_detach_source(&sc->sc_rndsource);
mutex_destroy(&sc->sc_lock);
- cv_destroy(&sc->sc_opencv);
+ cv_destroy(&sc->sc_statecv);
cv_destroy(&sc->sc_detachcv);
return 0;
@@ -544,7 +563,7 @@ ucomopen(dev_t dev, int flag, int mode,
{
const int unit = UCOMUNIT(dev);
struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
- int error;
+ int error = 0;
UCOMHIST_FUNC(); UCOMHIST_CALLED();
@@ -553,6 +572,7 @@ ucomopen(dev_t dev, int flag, int mode,
mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
mutex_exit(&sc->sc_lock);
return EIO;
}
@@ -575,29 +595,36 @@ ucomopen(dev_t dev, int flag, int mode,
* Wait while the device is initialized by the
* first opener or cleaned up by the last closer.
*/
- while (sc->sc_opening || sc->sc_closing) {
- error = cv_wait_sig(&sc->sc_opencv, &sc->sc_lock);
+ while (sc->sc_state == UCOM_OPENING || sc->sc_state == UCOM_CLOSING) {
+ error = cv_wait_sig(&sc->sc_statecv, &sc->sc_lock);
+
+ if (sc->sc_dying)
+ error = EIO;
if (error) {
mutex_exit(&sc->sc_lock);
return error;
}
}
+ enum ucom_state state = sc->sc_state;
- sc->sc_opening = 1;
+ KASSERTMSG(state == UCOM_OPEN || state == UCOM_ATTACHED,
+ "state is %d", state);
+ bool cleanup = false;
+ /* If this is the first open then perform the initialisation */
if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+ KASSERT(state == UCOM_ATTACHED);
tp->t_dev = dev;
+ cleanup = true;
+ sc->sc_state = UCOM_OPENING;
+ mutex_exit(&sc->sc_lock);
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;
- cv_signal(&sc->sc_opencv);
- mutex_exit(&sc->sc_lock);
- return error;
+ goto fail_2;
}
}
@@ -644,6 +671,13 @@ ucomopen(dev_t dev, int flag, int mode,
ucom_dtr(sc, 1);
ucom_rts(sc, 1);
+ mutex_enter(&sc->sc_lock);
+ if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
+ error = EIO;
+ goto fail_1;
+ }
+
sc->sc_rx_unblock = 0;
sc->sc_rx_stopped = 0;
sc->sc_tx_stopped = 0;
@@ -654,14 +688,18 @@ ucomopen(dev_t dev, int flag, int mode,
for (size_t i = 0; i < UCOM_IN_BUFFS; i++) {
struct ucom_buffer *ub = &sc->sc_ibuff[i];
error = ucomsubmitread(sc, ub);
- if (error)
+ if (error) {
+ mutex_exit(&sc->sc_lock);
goto fail_2;
+ }
}
}
- sc->sc_opening = 0;
- cv_signal(&sc->sc_opencv);
+ sc->sc_state = UCOM_OPEN;
+ cv_signal(&sc->sc_statecv);
mutex_exit(&sc->sc_lock);
+ DPRINTF("unit=%d, tp=%p dialout %d nonblock %d", unit, tp,
+ !!UCOMDIALOUT(dev), !!ISSET(flag, O_NONBLOCK));
error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
if (error)
goto bad;
@@ -672,30 +710,24 @@ ucomopen(dev_t dev, int flag, int mode,
return 0;
-fail_2:
- if (sc->sc_bulkin_no != -1)
- usbd_abort_pipe(sc->sc_bulkin_pipe);
- if (sc->sc_bulkout_no != -1)
- usbd_abort_pipe(sc->sc_bulkout_pipe);
-
- mutex_enter(&sc->sc_lock);
- sc->sc_opening = 0;
- cv_signal(&sc->sc_opencv);
- mutex_exit(&sc->sc_lock);
-
- return error;
-
bad:
- mutex_spin_enter(&tty_lock);
- CLR(tp->t_state, TS_BUSY);
- if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
+ cleanup = !ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0;
+
+fail_2:
+ if (cleanup) {
/*
- * We failed to open the device, and nobody else had it opened.
- * Clean up the state as appropriate.
+ * We failed to open the device, and nobody else had
+ * it opened. Clean up the state as appropriate.
*/
ucom_cleanup(sc);
}
- mutex_spin_exit(&tty_lock);
+
+ mutex_enter(&sc->sc_lock);
+
+fail_1:
+ sc->sc_state = state;
+ cv_signal(&sc->sc_statecv);
+ mutex_exit(&sc->sc_lock);
return error;
}
@@ -705,6 +737,7 @@ ucomclose(dev_t dev, int flag, int mode,
{
const int unit = UCOMUNIT(dev);
struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
+ int error = 0;
UCOMHIST_FUNC(); UCOMHIST_CALLED();
@@ -714,21 +747,44 @@ ucomclose(dev_t dev, int flag, int mode,
return 0;
mutex_enter(&sc->sc_lock);
- struct tty *tp = sc->sc_tty;
+ if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
+ mutex_exit(&sc->sc_lock);
+ return ENXIO;
+ }
+
+ /*
+ * Wait until any opens/closes have finished
+ */
+ while (sc->sc_state == UCOM_OPENING || sc->sc_state == UCOM_CLOSING) {
+ error = cv_wait_sig(&sc->sc_statecv, &sc->sc_lock);
+
+ if (sc->sc_dying)
+ error = EIO;
+
+ if (error) {
+ mutex_exit(&sc->sc_lock);
+ return error;
+ }
+ }
- while (sc->sc_closing)
- cv_wait(&sc->sc_opencv, &sc->sc_lock);
- sc->sc_closing = 1;
+ struct tty *tp = sc->sc_tty;
if (!ISSET(tp->t_state, TS_ISOPEN)) {
- goto out;
+ KASSERT(sc->sc_state == UCOM_ATTACHED);
+ mutex_exit(&sc->sc_lock);
+ return 0;
}
- sc->sc_refcnt++;
+ KASSERT(sc->sc_state == UCOM_OPEN);
+ sc->sc_state = UCOM_CLOSING;
+ mutex_exit(&sc->sc_lock);
(*tp->t_linesw->l_close)(tp, flag);
ttyclose(tp);
+ /* state when we're done - default to open */
+ enum ucom_state state = UCOM_OPEN;
if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
/*
* Although we got a last close, the device may still be in
@@ -736,21 +792,18 @@ ucomclose(dev_t dev, int flag, int mode,
* processes waiting for carrier on the non-dialout node.
*/
ucom_cleanup(sc);
+ if (sc->sc_methods->ucom_close != NULL)
+ sc->sc_methods->ucom_close(sc->sc_parent,
+ sc->sc_portno);
+ state = UCOM_ATTACHED;
}
- if (sc->sc_methods->ucom_close != NULL)
- sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
-
- if (--sc->sc_refcnt < 0)
- cv_broadcast(&sc->sc_detachcv);
-
-out:
- sc->sc_closing = 0;
- cv_signal(&sc->sc_opencv);
-
+ mutex_enter(&sc->sc_lock);
+ sc->sc_state = state;
+ cv_signal(&sc->sc_statecv);
mutex_exit(&sc->sc_lock);
- return 0;
+ return error;
}
int
@@ -767,6 +820,7 @@ ucomread(dev_t dev, struct uio *uio, int
mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
mutex_exit(&sc->sc_lock);
return EIO;
}
@@ -781,6 +835,7 @@ ucomread(dev_t dev, struct uio *uio, int
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
cv_broadcast(&sc->sc_detachcv);
+ DPRINTF("unit=%d refcnt %d", UCOMUNIT(dev), sc->sc_refcnt, 0, 0);
mutex_exit(&sc->sc_lock);
return error;
@@ -793,11 +848,14 @@ ucomwrite(dev_t dev, struct uio *uio, in
struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
int error;
+ UCOMHIST_FUNC(); UCOMHIST_CALLED();
+
if (sc == NULL)
return EIO;
mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
mutex_exit(&sc->sc_lock);
return EIO;
}
@@ -812,6 +870,7 @@ ucomwrite(dev_t dev, struct uio *uio, in
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
cv_broadcast(&sc->sc_detachcv);
+ DPRINTF("unit=%d refcnt %d", UCOMUNIT(dev), sc->sc_refcnt, 0, 0);
mutex_exit(&sc->sc_lock);
return error;
@@ -823,11 +882,14 @@ ucompoll(dev_t dev, int events, struct l
const int unit = UCOMUNIT(dev);
struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
+ UCOMHIST_FUNC(); UCOMHIST_CALLED();
+
if (sc == NULL)
return POLLHUP;
mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
mutex_exit(&sc->sc_lock);
return POLLHUP;
}
@@ -841,6 +903,7 @@ ucompoll(dev_t dev, int events, struct l
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
cv_broadcast(&sc->sc_detachcv);
+ DPRINTF("unit=%d refcnt %d", UCOMUNIT(dev), sc->sc_refcnt, 0, 0);
mutex_exit(&sc->sc_lock);
return revents;
@@ -862,11 +925,14 @@ ucomioctl(dev_t dev, u_long cmd, void *d
struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
int error;
+ UCOMHIST_FUNC(); UCOMHIST_CALLED();
+
if (sc == NULL)
return EIO;
mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
mutex_exit(&sc->sc_lock);
return EIO;
}
@@ -879,6 +945,7 @@ ucomioctl(dev_t dev, u_long cmd, void *d
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
cv_broadcast(&sc->sc_detachcv);
+ DPRINTF("unit=%d refcnt %d", UCOMUNIT(dev), sc->sc_refcnt, 0, 0);
mutex_exit(&sc->sc_lock);
return error;
@@ -913,7 +980,6 @@ ucom_do_ioctl(struct ucom_softc *sc, u_l
error = 0;
DPRINTF("our cmd=0x%08lx", cmd, 0, 0, 0);
- //mutex_enter(&tty_lock);
switch (cmd) {
case TIOCSBRK:
@@ -977,8 +1043,6 @@ ucom_do_ioctl(struct ucom_softc *sc, u_l
break;
}
- //mutex_exit(&tty_lock);
-
return error;
}
@@ -1008,12 +1072,13 @@ tiocm_to_ucom(struct ucom_softc *sc, u_l
SET(sc->sc_mcr, combits);
break;
}
+ u_char mcr = sc->sc_mcr;
mutex_exit(&sc->sc_lock);
if (how == TIOCMSET || ISSET(combits, UMCR_DTR))
- ucom_dtr(sc, (sc->sc_mcr & UMCR_DTR) != 0);
+ ucom_dtr(sc, (mcr & UMCR_DTR) != 0);
if (how == TIOCMSET || ISSET(combits, UMCR_RTS))
- ucom_rts(sc, (sc->sc_mcr & UMCR_RTS) != 0);
+ ucom_rts(sc, (mcr & UMCR_RTS) != 0);
}
static int
@@ -1089,13 +1154,20 @@ void
ucom_status_change(struct ucom_softc *sc)
{
struct tty *tp = sc->sc_tty;
- u_char old_msr;
if (sc->sc_methods->ucom_get_status != NULL) {
- old_msr = sc->sc_msr;
+ u_char msr, lsr;
+
sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno,
- &sc->sc_lsr, &sc->sc_msr);
- if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) {
+ &lsr, &msr);
+ mutex_enter(&sc->sc_lock);
+ u_char old_msr = sc->sc_msr;
+
+ sc->sc_lsr = lsr;
+ sc->sc_msr = msr;
+ mutex_exit(&sc->sc_lock);
+
+ if (ISSET((msr ^ old_msr), UMSR_DCD)) {
mutex_spin_enter(&timecounter_lock);
pps_capture(&sc->sc_pps_state);
pps_event(&sc->sc_pps_state,
@@ -1104,13 +1176,14 @@ ucom_status_change(struct ucom_softc *sc
PPS_CAPTURECLEAR);
mutex_spin_exit(&timecounter_lock);
- (*tp->t_linesw->l_modem)(tp,
- ISSET(sc->sc_msr, UMSR_DCD));
+ (*tp->t_linesw->l_modem)(tp, ISSET(msr, UMSR_DCD));
}
} else {
+ mutex_enter(&sc->sc_lock);
sc->sc_lsr = 0;
/* Assume DCD is present, if we have no chance to check it. */
sc->sc_msr = UMSR_DCD;
+ mutex_exit(&sc->sc_lock);
}
}
@@ -1119,16 +1192,28 @@ ucomparam(struct tty *tp, struct termios
{
const int unit = UCOMUNIT(tp->t_dev);
struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
- int error;
+ int error = 0;
UCOMHIST_FUNC(); UCOMHIST_CALLED();
- if (sc == NULL || sc->sc_dying)
+ if (sc == NULL)
+ return EIO;
+
+ mutex_enter(&sc->sc_lock);
+ if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
+ mutex_exit(&sc->sc_lock);
return EIO;
+ }
+
+ sc->sc_refcnt++;
+ mutex_exit(&sc->sc_lock);
/* Check requested parameters. */
- if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
- return EINVAL;
+ if (t->c_ispeed && t->c_ispeed != t->c_ospeed) {
+ error = EINVAL;
+ goto out;
+ }
/*
* For the console, always force CLOCAL and !HUPCL, so that the port
@@ -1145,8 +1230,9 @@ ucomparam(struct tty *tp, struct termios
* VMIN and VTIME.
*/
if (tp->t_ospeed == t->c_ospeed &&
- tp->t_cflag == t->c_cflag)
- return 0;
+ tp->t_cflag == t->c_cflag) {
+ goto out;
+ }
/* XXX lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag); */
@@ -1159,7 +1245,7 @@ ucomparam(struct tty *tp, struct termios
error = sc->sc_methods->ucom_param(sc->sc_parent, sc->sc_portno,
t);
if (error)
- return error;
+ goto out;
}
/* XXX worry about CHWFLOW */
@@ -1181,6 +1267,13 @@ XXX what if the hardware is not open
}
}
#endif
+out:
+ mutex_enter(&sc->sc_lock);
+ if (--sc->sc_refcnt < 0)
+ cv_broadcast(&sc->sc_detachcv);
+ DPRINTF("unit=%d refcnt %d", UCOMUNIT(tp->t_dev), sc->sc_refcnt, 0, 0);
+
+ mutex_exit(&sc->sc_lock);
return 0;
}
@@ -1192,6 +1285,8 @@ ucomhwiflow(struct tty *tp, int block)
struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
int old;
+ UCOMHIST_FUNC(); UCOMHIST_CALLED();
+
if (sc == NULL)
return 0;
@@ -1217,12 +1312,15 @@ ucomstart(struct tty *tp)
u_char *data;
int cnt;
+ UCOMHIST_FUNC(); UCOMHIST_CALLED();
+
if (sc == NULL)
return;
KASSERT(&sc->sc_lock);
KASSERT(mutex_owned(&tty_lock));
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
return;
}
@@ -1269,6 +1367,7 @@ ucomstart(struct tty *tp)
softint_schedule(sc->sc_si);
out:
+ DPRINTF("... done", 0, 0, 0, 0);
return;
}
@@ -1365,9 +1464,17 @@ ucomwritecb(struct usbd_xfer *xfer, void
static void
ucom_softintr(void *arg)
{
+ UCOMHIST_FUNC(); UCOMHIST_CALLED();
+
struct ucom_softc *sc = arg;
mutex_enter(&sc->sc_lock);
+ if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
+ mutex_exit(&sc->sc_lock);
+ return;
+ }
+
struct tty *tp = sc->sc_tty;
mutex_enter(&tty_lock);
if (!ISSET(tp->t_state, TS_ISOPEN)) {
@@ -1457,12 +1564,13 @@ ucomreadcb(struct usbd_xfer *xfer, void
UCOMHIST_FUNC(); UCOMHIST_CALLED();
- if (status == USBD_CANCELLED)
+ if (status == USBD_CANCELLED) {
+ DPRINTF("... done (cancelled status %d)", status, 0, 0, 0);
return;
+ }
mutex_enter(&sc->sc_lock);
- if (status == USBD_IOERROR ||
- sc->sc_dying) {
+ if (status == USBD_IOERROR || sc->sc_dying) {
DPRINTF("dying", 0, 0, 0, 0);
/* Send something to wake upper layer */
(tp->t_linesw->l_rint)('\n', tp);
@@ -1476,18 +1584,20 @@ ucomreadcb(struct usbd_xfer *xfer, void
ub = SIMPLEQ_FIRST(&sc->sc_ibuff_empty);
SIMPLEQ_REMOVE_HEAD(&sc->sc_ibuff_empty, ub_link);
- if (status == USBD_STALLED) {
- if (sc->sc_bulkin_no != -1)
- usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
- if (sc->sc_ipipe)
- usbd_clear_endpoint_stall_async(sc->sc_ipipe);
- ucomsubmitread(sc, ub);
- mutex_exit(&sc->sc_lock);
- return;
- }
-
if (status != USBD_NORMAL_COMPLETION) {
- printf("ucomreadcb: wonky status=%s\n", usbd_errstr(status));
+ if (status == USBD_STALLED) {
+ if (sc->sc_bulkin_no != -1)
+ usbd_clear_endpoint_stall_async(sc->sc_bulkin_pipe);
+ if (sc->sc_ipipe)
+ usbd_clear_endpoint_stall_async(sc->sc_ipipe);
+ } else {
+ printf("ucomreadcb: wonky status=%s\n",
+ usbd_errstr(status));
+ }
+
+ DPRINTF("... done (status %d)", status, 0, 0, 0);
+ /* re-adds ub to sc_ibuff_empty */
+ ucomsubmitread(sc, ub);
mutex_exit(&sc->sc_lock);
return;
}
@@ -1505,9 +1615,11 @@ ucomreadcb(struct usbd_xfer *xfer, void
rnd_add_uint32(&sc->sc_rndsource, cc);
- if (sc->sc_opening) {
+ if (sc->sc_state != UCOM_OPEN) {
+ /* Go around again - we're not quite ready */
ucomsubmitread(sc, ub);
mutex_exit(&sc->sc_lock);
+ DPRINTF("... done (not open)", 0, 0, 0, 0);
return;
}
@@ -1525,6 +1637,8 @@ ucomreadcb(struct usbd_xfer *xfer, void
ucom_read_complete(sc);
mutex_exit(&sc->sc_lock);
+
+ DPRINTF("... done", 0, 0, 0, 0);
}
static void
@@ -1535,9 +1649,20 @@ ucom_cleanup(struct ucom_softc *sc)
DPRINTF("aborting pipes", 0, 0, 0, 0);
- KASSERT(mutex_owned(&sc->sc_lock));
+ mutex_enter(&sc->sc_lock);
+
+ /* If we're dying then the detach routine will abort our pipes, etc */
+ if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
+
+ mutex_exit(&sc->sc_lock);
+ return;
+ }
ucom_shutdown(sc);
+
+ mutex_exit(&sc->sc_lock);
+
if (sc->sc_bulkin_pipe != NULL) {
usbd_abort_pipe(sc->sc_bulkin_pipe);
}