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/uchcom.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/uchcom.c')
-rw-r--r-- | sys/dev/usb/serial/uchcom.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/sys/dev/usb/serial/uchcom.c b/sys/dev/usb/serial/uchcom.c index b592497..e62a13c 100644 --- a/sys/dev/usb/serial/uchcom.c +++ b/sys/dev/usb/serial/uchcom.c @@ -211,6 +211,7 @@ static const STRUCT_USB_HOST_ID uchcom_devs[] = { /* protypes */ +static void uchcom_free(struct ucom_softc *); static int uchcom_pre_param(struct ucom_softc *, struct termios *); static void uchcom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *); @@ -234,6 +235,7 @@ static void uchcom_poll(struct ucom_softc *ucom); static device_probe_t uchcom_probe; static device_attach_t uchcom_attach; static device_detach_t uchcom_detach; +static device_free_softc_t uchcom_free_softc; static usb_callback_t uchcom_intr_callback; static usb_callback_t uchcom_write_callback; @@ -282,6 +284,7 @@ static struct ucom_callback uchcom_callback = { .ucom_start_write = &uchcom_start_write, .ucom_stop_write = &uchcom_stop_write, .ucom_poll = &uchcom_poll, + .ucom_free = &uchcom_free, }; /* ---------------------------------------------------------------------- @@ -319,6 +322,7 @@ uchcom_attach(device_t dev) device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "uchcom", NULL, MTX_DEF); + ucom_ref(&sc->sc_super_ucom); sc->sc_udev = uaa->device; @@ -371,11 +375,30 @@ uchcom_detach(device_t dev) ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); usbd_transfer_unsetup(sc->sc_xfer, UCHCOM_N_TRANSFER); - mtx_destroy(&sc->sc_mtx); return (0); } +UCOM_UNLOAD_DRAIN(uchcom); + +static void +uchcom_free_softc(device_t dev, void *arg) +{ + struct uchcom_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 +uchcom_free(struct ucom_softc *ucom) +{ + uchcom_free_softc(NULL, ucom->sc_parent); +} + /* ---------------------------------------------------------------------- * low level i/o */ @@ -841,8 +864,8 @@ static device_method_t uchcom_methods[] = { DEVMETHOD(device_probe, uchcom_probe), DEVMETHOD(device_attach, uchcom_attach), DEVMETHOD(device_detach, uchcom_detach), - - {0, 0} + DEVMETHOD(device_free_softc, uchcom_free_softc), + DEVMETHOD_END }; static driver_t uchcom_driver = { |