summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/serial/uvisor.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2012-08-10 15:29:41 +0000
committerhselasky <hselasky@FreeBSD.org>2012-08-10 15:29:41 +0000
commit6f292b5574ac475585d410a406b2bfef24d18e76 (patch)
tree49b87629c9a67f08dce84f6b5c6c4b928b728c75 /sys/dev/usb/serial/uvisor.c
parentcb58ff63759853c9bb4b0484d5b87f636eacd93a (diff)
downloadFreeBSD-src-6f292b5574ac475585d410a406b2bfef24d18e76.zip
FreeBSD-src-6f292b5574ac475585d410a406b2bfef24d18e76.tar.gz
Take advantage of new UCOM and bus functionality so that
the device_detach() function doesn't block on UCOM device drivers until the TTY handle is closed by the userspace application. This is implemented by a postpone of the softc free where the UCOM structures reside until the TTY references are gone. Discussed with: kib, ed MFC after: 2 weeks
Diffstat (limited to 'sys/dev/usb/serial/uvisor.c')
-rw-r--r--sys/dev/usb/serial/uvisor.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/sys/dev/usb/serial/uvisor.c b/sys/dev/usb/serial/uvisor.c
index df96958..4f3426b 100644
--- a/sys/dev/usb/serial/uvisor.c
+++ b/sys/dev/usb/serial/uvisor.c
@@ -189,12 +189,14 @@ struct uvisor_softc {
static device_probe_t uvisor_probe;
static device_attach_t uvisor_attach;
static device_detach_t uvisor_detach;
+static device_free_softc_t uvisor_free_softc;
static usb_callback_t uvisor_write_callback;
static usb_callback_t uvisor_read_callback;
static usb_error_t uvisor_init(struct uvisor_softc *, struct usb_device *,
struct usb_config *);
+static void uvisor_free(struct ucom_softc *);
static void uvisor_cfg_open(struct ucom_softc *);
static void uvisor_cfg_close(struct ucom_softc *);
static void uvisor_start_read(struct ucom_softc *);
@@ -231,13 +233,15 @@ static const struct ucom_callback uvisor_callback = {
.ucom_stop_read = &uvisor_stop_read,
.ucom_start_write = &uvisor_start_write,
.ucom_stop_write = &uvisor_stop_write,
+ .ucom_free = &uvisor_free,
};
static device_method_t uvisor_methods[] = {
DEVMETHOD(device_probe, uvisor_probe),
DEVMETHOD(device_attach, uvisor_attach),
DEVMETHOD(device_detach, uvisor_detach),
- {0, 0}
+ DEVMETHOD(device_free_softc, uvisor_free_softc),
+ DEVMETHOD_END
};
static devclass_t uvisor_devclass;
@@ -317,6 +321,7 @@ uvisor_attach(device_t dev)
device_set_usb_desc(dev);
mtx_init(&sc->sc_mtx, "uvisor", NULL, MTX_DEF);
+ ucom_ref(&sc->sc_super_ucom);
sc->sc_udev = uaa->device;
@@ -365,11 +370,30 @@ uvisor_detach(device_t dev)
ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
usbd_transfer_unsetup(sc->sc_xfer, UVISOR_N_TRANSFER);
- mtx_destroy(&sc->sc_mtx);
return (0);
}
+UCOM_UNLOAD_DRAIN(uvisor);
+
+static void
+uvisor_free_softc(device_t dev, void *arg)
+{
+ struct uvisor_softc *sc = arg;
+
+ if (ucom_unref(&sc->sc_super_ucom)) {
+ if (mtx_initialized(&sc->sc_mtx))
+ mtx_destroy(&sc->sc_mtx);
+ device_free_softc(dev, sc);
+ }
+}
+
+static void
+uvisor_free(struct ucom_softc *ucom)
+{
+ uvisor_free_softc(NULL, ucom->sc_parent);
+}
+
static usb_error_t
uvisor_init(struct uvisor_softc *sc, struct usb_device *udev, struct usb_config *config)
{
OpenPOWER on IntegriCloud