Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb Pull across various locking and reference counti...
details: https://anonhg.NetBSD.org/src/rev/4bf56cdcc9e0
branches: trunk
changeset: 348993:4bf56cdcc9e0
user: skrll <skrll%NetBSD.org@localhost>
date: Sat Nov 19 09:49:20 2016 +0000
description:
Pull across various locking and reference counting fixes from nick-nhusb.
diffstat:
sys/dev/usb/ucom.c | 515 ++++++++++++++++++++++++++++++++++------------------
1 files changed, 335 insertions(+), 180 deletions(-)
diffs (truncated from 1112 to 300 lines):
diff -r 0843f5d02493 -r 4bf56cdcc9e0 sys/dev/usb/ucom.c
--- a/sys/dev/usb/ucom.c Sat Nov 19 09:46:58 2016 +0000
+++ b/sys/dev/usb/ucom.c Sat Nov 19 09:49:20 2016 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ucom.c,v 1.114 2016/10/03 13:36:33 skrll Exp $ */
+/* $NetBSD: ucom.c,v 1.115 2016/11/19 09:49:20 skrll Exp $ */
/*
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.114 2016/10/03 13:36:33 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.115 2016/11/19 09:49:20 skrll Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_usb.h"
+#endif
#include <sys/param.h>
#include <sys/systm.h>
@@ -139,11 +143,10 @@
device_t sc_dev; /* base device */
struct usbd_device * sc_udev; /* USB device */
-
struct usbd_interface * sc_iface; /* data interface */
int sc_bulkin_no; /* bulk in endpoint address */
- struct usbd_pipe * sc_bulkin_pipe; /* bulk in pipe */
+ struct usbd_pipe * sc_bulkin_pipe;/* bulk in pipe */
u_int sc_ibufsize; /* read buffer size */
u_int sc_ibufsizepad; /* read buffer size padded */
struct ucom_buffer sc_ibuff[UCOM_IN_BUFFS];
@@ -173,17 +176,22 @@
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;
- u_char sc_dying; /* disconnecting */
+ bool sc_dying; /* disconnecting */
struct pps_state sc_pps_state; /* pps state */
krndsource_t sc_rndsource; /* random source */
kmutex_t sc_lock;
- kcondvar_t sc_opencv;
+ kcondvar_t sc_statecv;
kcondvar_t sc_detachcv;
};
@@ -227,11 +235,11 @@
static void ucomreadcb(struct usbd_xfer *, void *, usbd_status);
static void ucom_submit_write(struct ucom_softc *, struct ucom_buffer *);
static void ucom_write_status(struct ucom_softc *, struct ucom_buffer *,
- usbd_status);
+ usbd_status);
static void ucomwritecb(struct usbd_xfer *, void *, usbd_status);
static void ucom_read_complete(struct ucom_softc *);
-static usbd_status ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
+static int ucomsubmitread(struct ucom_softc *, struct ucom_buffer *);
static void ucom_softintr(void *);
int ucom_match(device_t, cfdata_t, void *);
@@ -253,7 +261,6 @@
{
struct ucom_softc *sc = device_private(self);
struct ucom_attach_args *ucaa = aux;
- struct tty *tp;
UCOMHIST_FUNC(); UCOMHIST_CALLED();
@@ -282,14 +289,13 @@
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 = 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);
@@ -316,6 +322,17 @@
error = EIO;
goto fail_0;
}
+ /* Allocate input buffers */
+ for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
+ ub++) {
+ error = usbd_create_xfer(sc->sc_bulkin_pipe,
+ sc->sc_ibufsizepad, USBD_SHORT_XFER_OK, 0,
+ &ub->ub_xfer);
+ if (error)
+ goto fail_1;
+ ub->ub_data = usbd_get_buffer(ub->ub_xfer);
+ }
+
err = usbd_open_pipe(sc->sc_iface, sc->sc_bulkout_no,
USBD_EXCLUSIVE_USE, &sc->sc_bulkout_pipe);
if (err) {
@@ -324,28 +341,17 @@
error = EIO;
goto fail_1;
}
-
- /* Allocate input buffers */
- for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
- ub++) {
- error = usbd_create_xfer(sc->sc_bulkin_pipe, sc->sc_ibufsizepad,
- USBD_SHORT_XFER_OK, 0, &ub->ub_xfer);
- if (error)
- goto fail_2;
- ub->ub_data = usbd_get_buffer(ub->ub_xfer);
- }
-
for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
ub++) {
- error = usbd_create_xfer(sc->sc_bulkout_pipe, sc->sc_obufsize,
- 0, 0, &ub->ub_xfer);
+ error = usbd_create_xfer(sc->sc_bulkout_pipe,
+ sc->sc_obufsize, 0, 0, &ub->ub_xfer);
if (error)
goto fail_2;
ub->ub_data = usbd_get_buffer(ub->ub_xfer);
SIMPLEQ_INSERT_TAIL(&sc->sc_obuff_free, ub, ub_link);
}
- tp = tty_alloc();
+ struct tty *tp = tty_alloc();
tp->t_oproc = ucomstart;
tp->t_param = ucomparam;
tp->t_hwiflow = ucomhwiflow;
@@ -359,21 +365,26 @@
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:
- for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
- ub++) {
- if (ub->ub_xfer)
- usbd_destroy_xfer(ub->ub_xfer);
- }
for (ub = &sc->sc_obuff[0]; ub != &sc->sc_obuff[UCOM_OUT_BUFFS];
ub++) {
if (ub->ub_xfer)
usbd_destroy_xfer(ub->ub_xfer);
}
+ usbd_close_pipe(sc->sc_bulkout_pipe);
+
fail_1:
+ for (ub = &sc->sc_ibuff[0]; ub != &sc->sc_ibuff[UCOM_IN_BUFFS];
+ ub++) {
+ if (ub->ub_xfer)
+ usbd_destroy_xfer(ub->ub_xfer);
+ }
usbd_close_pipe(sc->sc_bulkin_pipe);
fail_0:
@@ -393,10 +404,10 @@
UCOMHIST_FUNC(); UCOMHIST_CALLED();
DPRINTF("sc=%p flags=%d tp=%p", sc, flags, tp, 0);
- DPRINTF("... pipe=%d,%d",sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
+ DPRINTF("... pipe=%d,%d", sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
mutex_enter(&sc->sc_lock);
- sc->sc_dying = 1;
+ sc->sc_dying = true;
mutex_exit(&sc->sc_lock);
pmf_device_deregister(self);
@@ -407,6 +418,18 @@
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) {
@@ -417,7 +440,10 @@
mutex_spin_exit(&tty_lock);
}
/* Wait for processes to go away. */
- usb_detach_wait(sc->sc_dev, &sc->sc_detachcv, &sc->sc_lock);
+ if (cv_timedwait(&sc->sc_detachcv, &sc->sc_lock, hz * 60)) {
+ printf("%s: %s didn't detach\n", __func__,
+ device_xname(sc->sc_dev));
+ }
}
softint_disestablish(sc->sc_si);
@@ -428,7 +454,7 @@
/* Nuke the vnodes for any open instances. */
mn = device_unit(self);
- DPRINTF("maj=%d mn=%d\n", maj, mn, 0, 0);
+ DPRINTF("maj=%d mn=%d", maj, mn, 0, 0);
vdevgone(maj, mn, mn, VCHR);
vdevgone(maj, mn | UCOMDIALOUT_MASK, mn | UCOMDIALOUT_MASK, VCHR);
vdevgone(maj, mn | UCOMCALLUNIT_MASK, mn | UCOMCALLUNIT_MASK, VCHR);
@@ -464,7 +490,7 @@
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;
@@ -482,7 +508,7 @@
switch (act) {
case DVACT_DEACTIVATE:
mutex_enter(&sc->sc_lock);
- sc->sc_dying = 1;
+ sc->sc_dying = true;
mutex_exit(&sc->sc_lock);
return 0;
default:
@@ -512,11 +538,9 @@
int
ucomopen(dev_t dev, int flag, int mode, struct lwp *l)
{
- int unit = UCOMUNIT(dev);
- struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
- struct ucom_buffer *ub;
- struct tty *tp;
- int error;
+ const int unit = UCOMUNIT(dev);
+ struct ucom_softc * const sc = device_lookup_private(&ucom_cd, unit);
+ int error = 0;
UCOMHIST_FUNC(); UCOMHIST_CALLED();
@@ -525,6 +549,7 @@
mutex_enter(&sc->sc_lock);
if (sc->sc_dying) {
+ DPRINTF("... dying", 0, 0, 0, 0);
mutex_exit(&sc->sc_lock);
return EIO;
}
@@ -534,9 +559,9 @@
return ENXIO;
}
- tp = sc->sc_tty;
+ struct tty *tp = sc->sc_tty;
- DPRINTF("unit=%d, tp=%p\n", unit, tp, 0, 0);
+ DPRINTF("unit=%d, tp=%p", unit, tp, 0, 0);
if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
mutex_exit(&sc->sc_lock);
@@ -547,31 +572,36 @@
* 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)
Home |
Main Index |
Thread Index |
Old Index