diff options
author | hselasky <hselasky@FreeBSD.org> | 2012-08-10 15:29:41 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2012-08-10 15:29:41 +0000 |
commit | 6f292b5574ac475585d410a406b2bfef24d18e76 (patch) | |
tree | 49b87629c9a67f08dce84f6b5c6c4b928b728c75 /sys/dev/usb/serial/umct.c | |
parent | cb58ff63759853c9bb4b0484d5b87f636eacd93a (diff) | |
download | FreeBSD-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.c | 28 |
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) |