summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/serial/umct.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/umct.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/umct.c')
-rw-r--r--sys/dev/usb/serial/umct.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/sys/dev/usb/serial/umct.c b/sys/dev/usb/serial/umct.c
index 16dd4a1..eaab705 100644
--- a/sys/dev/usb/serial/umct.c
+++ b/sys/dev/usb/serial/umct.c
@@ -123,6 +123,7 @@ struct umct_softc {
static device_probe_t umct_probe;
static device_attach_t umct_attach;
static device_detach_t umct_detach;
+static device_free_softc_t umct_free_softc;
static usb_callback_t umct_intr_callback;
static usb_callback_t umct_intr_callback_sub;
@@ -132,6 +133,7 @@ static usb_callback_t umct_write_callback;
static void umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
uint16_t len, uint32_t value);
+static void umct_free(struct ucom_softc *);
static void umct_cfg_get_status(struct ucom_softc *, uint8_t *,
uint8_t *);
static void umct_cfg_set_break(struct ucom_softc *, uint8_t);
@@ -190,6 +192,7 @@ static const struct ucom_callback umct_callback = {
.ucom_start_write = &umct_start_write,
.ucom_stop_write = &umct_stop_write,
.ucom_poll = &umct_poll,
+ .ucom_free = &umct_free,
};
static const STRUCT_USB_HOST_ID umct_devs[] = {
@@ -204,7 +207,8 @@ static device_method_t umct_methods[] = {
DEVMETHOD(device_probe, umct_probe),
DEVMETHOD(device_attach, umct_attach),
DEVMETHOD(device_detach, umct_detach),
- {0, 0}
+ DEVMETHOD(device_free_softc, umct_free_softc),
+ DEVMETHOD_END
};
static devclass_t umct_devclass;
@@ -251,6 +255,7 @@ umct_attach(device_t dev)
device_set_usb_desc(dev);
mtx_init(&sc->sc_mtx, "umct", NULL, MTX_DEF);
+ ucom_ref(&sc->sc_super_ucom);
snprintf(sc->sc_name, sizeof(sc->sc_name),
"%s", device_get_nameunit(dev));
@@ -312,11 +317,30 @@ umct_detach(device_t dev)
ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
usbd_transfer_unsetup(sc->sc_xfer, UMCT_N_TRANSFER);
- mtx_destroy(&sc->sc_mtx);
return (0);
}
+UCOM_UNLOAD_DRAIN(umct);
+
+static void
+umct_free_softc(device_t dev, void *arg)
+{
+ struct umct_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
+umct_free(struct ucom_softc *ucom)
+{
+ umct_free_softc(NULL, ucom->sc_parent);
+}
+
static void
umct_cfg_do_request(struct umct_softc *sc, uint8_t request,
uint16_t len, uint32_t value)
OpenPOWER on IntegriCloud