summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2004-08-02 15:37:35 +0000
committeriedowse <iedowse@FreeBSD.org>2004-08-02 15:37:35 +0000
commit4d8c7e278116822a79a8e6f3289597805631b781 (patch)
treef9651ebefb22b158edbbdb2ae4fbc1c3857d340a
parentfb7f90d7ec95dc92cb81c6e9b8768b90f31666ad (diff)
downloadFreeBSD-src-4d8c7e278116822a79a8e6f3289597805631b781.zip
FreeBSD-src-4d8c7e278116822a79a8e6f3289597805631b781.tar.gz
Make the USB subsystem unloadable and detachable, though currently
a significant amount of memory may be leaked each time a host controller is detached.
-rw-r--r--sys/dev/usb/ehci.c22
-rw-r--r--sys/dev/usb/ehci_pci.c45
-rw-r--r--sys/dev/usb/ehcivar.h6
-rw-r--r--sys/dev/usb/ohci.c16
-rw-r--r--sys/dev/usb/ohci_pci.c20
-rw-r--r--sys/dev/usb/ohcivar.h5
-rw-r--r--sys/dev/usb/uhci.c17
-rw-r--r--sys/dev/usb/uhci_pci.c24
-rw-r--r--sys/dev/usb/uhcivar.h5
-rw-r--r--sys/dev/usb/uhub.c3
-rw-r--r--sys/dev/usb/usb.c71
11 files changed, 158 insertions, 76 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index ed371c3..460efed 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -168,10 +168,6 @@ struct ehci_pipe {
} u;
};
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-Static void ehci_power(int, void *);
-#endif
-
Static usbd_status ehci_open(usbd_pipe_handle);
Static void ehci_poll(struct usbd_bus *);
Static void ehci_softintr(void *);
@@ -929,32 +925,38 @@ ehci_poll(struct usbd_bus *bus)
ehci_intr1(sc);
}
-#if defined(__NetBSD__) || defined(__OpenBSD__)
int
ehci_detach(struct ehci_softc *sc, int flags)
{
int rv = 0;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
if (rv != 0)
return (rv);
+#endif
+ EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
+ EOWRITE4(sc, EHCI_USBCMD, 0);
+ EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET);
usb_uncallout(sc->sc_tmo_pcd, ehci_pcd_enable, sc);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
if (sc->sc_powerhook != NULL)
powerhook_disestablish(sc->sc_powerhook);
if (sc->sc_shutdownhook != NULL)
shutdownhook_disestablish(sc->sc_shutdownhook);
+#endif
usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
+ usb_freemem(&sc->sc_bus, &sc->sc_fldma);
/* XXX free other data structures XXX */
return (rv);
}
-#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
int
@@ -981,10 +983,9 @@ ehci_activate(device_ptr_t self, enum devact act)
* Handle suspend/resume.
*
* We need to switch to polling mode here, because this routine is
- * called from an intterupt context. This is all right since we
+ * called from an interrupt context. This is all right since we
* are almost suspended anyway.
*/
-#if defined(__NetBSD__) || defined(__OpenBSD__)
void
ehci_power(int why, void *v)
{
@@ -1000,7 +1001,9 @@ ehci_power(int why, void *v)
s = splhardusb();
switch (why) {
case PWR_SUSPEND:
+#if defined(__NetBSD__) || defined(__OpenBSD__)
case PWR_STANDBY:
+#endif
sc->sc_bus.use_polling++;
#if 0
OOO
@@ -1044,14 +1047,15 @@ OOO
#endif
sc->sc_bus.use_polling--;
break;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
case PWR_SOFTSUSPEND:
case PWR_SOFTSTANDBY:
case PWR_SOFTRESUME:
break;
+#endif
}
splx(s);
}
-#endif
/*
* Shut down the controller when the system is going down.
diff --git a/sys/dev/usb/ehci_pci.c b/sys/dev/usb/ehci_pci.c
index 482f187..5b1b1f1 100644
--- a/sys/dev/usb/ehci_pci.c
+++ b/sys/dev/usb/ehci_pci.c
@@ -102,10 +102,38 @@ static const char *ehci_device_generic = "EHCI (generic) USB 2.0 controller";
static int ehci_pci_attach(device_t self);
static int ehci_pci_detach(device_t self);
static int ehci_pci_shutdown(device_t self);
+static int ehci_pci_suspend(device_t self);
+static int ehci_pci_resume(device_t self);
static void ehci_pci_givecontroller(device_t self);
static void ehci_pci_takecontroller(device_t self);
static int
+ehci_pci_suspend(device_t self)
+{
+ ehci_softc_t *sc = device_get_softc(self);
+ int err;
+
+ err = bus_generic_suspend(self);
+ if (err)
+ return (err);
+ ehci_power(PWR_SUSPEND, sc);
+
+ return 0;
+}
+
+static int
+ehci_pci_resume(device_t self)
+{
+ ehci_softc_t *sc = device_get_softc(self);
+
+ ehci_pci_takecontroller(self);
+ ehci_power(PWR_RESUME, sc);
+ bus_generic_resume(self);
+
+ return 0;
+}
+
+static int
ehci_pci_shutdown(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
@@ -296,14 +324,14 @@ ehci_pci_attach(device_t self)
ehci_pci_takecontroller(self);
err = ehci_init(sc);
- if (!err)
+ if (!err) {
+ sc->sc_flags |= EHCI_SCFLG_DONEINIT;
err = device_probe_and_attach(sc->sc_bus.bdev);
+ }
if (err) {
device_printf(self, "USB init failed err=%d\n", err);
-#if 0 /* TODO */
ehci_pci_detach(self);
-#endif
return EIO;
}
return 0;
@@ -314,10 +342,10 @@ ehci_pci_detach(device_t self)
{
ehci_softc_t *sc = device_get_softc(self);
- /*
- * XXX this code is not yet fit to be used as detach for the EHCI
- * controller
- */
+ if (sc->sc_flags & EHCI_SCFLG_DONEINIT) {
+ ehci_detach(sc, 0);
+ sc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
+ }
/*
* disable interrupts that might have been switched on in ehci_init
@@ -406,6 +434,9 @@ static device_method_t ehci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ehci_pci_probe),
DEVMETHOD(device_attach, ehci_pci_attach),
+ DEVMETHOD(device_detach, ehci_pci_detach),
+ DEVMETHOD(device_suspend, ehci_pci_suspend),
+ DEVMETHOD(device_resume, ehci_pci_resume),
DEVMETHOD(device_shutdown, ehci_pci_shutdown),
/* Bus interface */
diff --git a/sys/dev/usb/ehcivar.h b/sys/dev/usb/ehcivar.h
index 318d835..5cd3f58 100644
--- a/sys/dev/usb/ehcivar.h
+++ b/sys/dev/usb/ehcivar.h
@@ -87,8 +87,11 @@ struct ehci_soft_islot {
#define EHCI_HASH_SIZE 128
#define EHCI_COMPANION_MAX 8
+#define EHCI_SCFLG_DONEINIT 0x0001 /* ehci_init() has been called. */
+
typedef struct ehci_softc {
struct usbd_bus sc_bus; /* base device */
+ int sc_flags;
bus_space_tag_t iot;
bus_space_handle_t ioh;
bus_size_t sc_size;
@@ -161,10 +164,11 @@ typedef struct ehci_softc {
usbd_status ehci_init(ehci_softc_t *);
int ehci_intr(void *);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
int ehci_detach(ehci_softc_t *, int);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int ehci_activate(device_ptr_t, enum devact);
#endif
+void ehci_power(int state, void *priv);
void ehci_shutdown(void *v);
#define MS_TO_TICKS(ms) ((ms) * hz / 1000)
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index a8dfe3f..9de8479 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -382,17 +382,20 @@ ohci_activate(device_ptr_t self, enum devact act)
}
return (rv);
}
+#endif
int
ohci_detach(struct ohci_softc *sc, int flags)
{
- int rv = 0;
+ int i, rv = 0;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
if (rv != 0)
return (rv);
+#endif
usb_uncallout(sc->sc_tmo_rhsc, ohci_rhsc_enable, sc);
@@ -401,13 +404,20 @@ ohci_detach(struct ohci_softc *sc, int flags)
shutdownhook_disestablish(sc->sc_shutdownhook);
#endif
+ OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+ OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
+
usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
- /* free data structures XXX */
+ for (i = 0; i < OHCI_NO_EDS; i++)
+ ohci_free_sed(sc, sc->sc_eds[i]);
+ ohci_free_sed(sc, sc->sc_isoc_head);
+ ohci_free_sed(sc, sc->sc_bulk_head);
+ ohci_free_sed(sc, sc->sc_ctrl_head);
+ usb_freemem(&sc->sc_bus, &sc->sc_hccadma);
return (rv);
}
-#endif
ohci_soft_ed_t *
ohci_alloc_sed(ohci_softc_t *sc)
diff --git a/sys/dev/usb/ohci_pci.c b/sys/dev/usb/ohci_pci.c
index 0aa9f5d..6700323 100644
--- a/sys/dev/usb/ohci_pci.c
+++ b/sys/dev/usb/ohci_pci.c
@@ -290,8 +290,10 @@ ohci_pci_attach(device_t self)
return ENXIO;
}
err = ohci_init(sc);
- if (!err)
+ if (!err) {
+ sc->sc_flags |= OHCI_SCFLG_DONEINIT;
err = device_probe_and_attach(sc->sc_bus.bdev);
+ }
if (err) {
device_printf(self, "USB init failed\n");
@@ -306,17 +308,10 @@ ohci_pci_detach(device_t self)
{
ohci_softc_t *sc = device_get_softc(self);
- /*
- * XXX this code is not yet fit to be used as detach for the OHCI
- * controller
- */
-
- /*
- * disable interrupts that might have been switched on in ohci_init
- */
- if (sc->iot && sc->ioh)
- bus_space_write_4(sc->iot, sc->ioh,
- OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+ if (sc->sc_flags & OHCI_SCFLG_DONEINIT) {
+ ohci_detach(sc, 0);
+ sc->sc_flags &= ~OHCI_SCFLG_DONEINIT;
+ }
if (sc->irq_res && sc->ih) {
int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
@@ -348,6 +343,7 @@ static device_method_t ohci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, ohci_pci_probe),
DEVMETHOD(device_attach, ohci_pci_attach),
+ DEVMETHOD(device_detach, ohci_pci_detach),
DEVMETHOD(device_suspend, ohci_pci_suspend),
DEVMETHOD(device_resume, ohci_pci_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
diff --git a/sys/dev/usb/ohcivar.h b/sys/dev/usb/ohcivar.h
index 84b5447..19ec182 100644
--- a/sys/dev/usb/ohcivar.h
+++ b/sys/dev/usb/ohcivar.h
@@ -83,8 +83,11 @@ typedef struct ohci_soft_itd {
#define OHCI_HASH_SIZE 128
+#define OHCI_SCFLG_DONEINIT 0x0001 /* ohci_init() done. */
+
typedef struct ohci_softc {
struct usbd_bus sc_bus; /* base device */
+ int sc_flags;
bus_space_tag_t iot;
bus_space_handle_t ioh;
bus_size_t sc_size;
@@ -159,8 +162,8 @@ struct ohci_xfer {
usbd_status ohci_init(ohci_softc_t *);
int ohci_intr(void *);
+int ohci_detach(ohci_softc_t *, int);
#if defined(__NetBSD__) || defined(__OpenBSD__)
-int ohci_detach(ohci_softc_t *, int);
int ohci_activate(device_ptr_t, enum devact);
#endif
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 5aab519..bf10d19 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -572,6 +572,7 @@ uhci_activate(device_ptr_t self, enum devact act)
}
return (rv);
}
+#endif
int
uhci_detach(struct uhci_softc *sc, int flags)
@@ -579,11 +580,16 @@ uhci_detach(struct uhci_softc *sc, int flags)
usbd_xfer_handle xfer;
int rv = 0;
+#if defined(__NetBSD__) || defined(__OpenBSD__)
if (sc->sc_child != NULL)
rv = config_detach(sc->sc_child, flags);
if (rv != 0)
return (rv);
+#endif
+
+ UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
+ uhci_run(sc, 0);
#if defined(__NetBSD__) || defined(__OpenBSD__)
powerhook_disestablish(sc->sc_powerhook);
@@ -600,10 +606,10 @@ uhci_detach(struct uhci_softc *sc, int flags)
}
/* XXX free other data structures XXX */
+ usb_freemem(&sc->sc_bus, &sc->sc_dma);
return (rv);
}
-#endif
usbd_status
uhci_allocm(struct usbd_bus *bus, usb_dma_t *dma, u_int32_t size)
@@ -638,6 +644,8 @@ uhci_allocx(struct usbd_bus *bus)
if (xfer != NULL) {
memset(xfer, 0, sizeof (struct uhci_xfer));
UXFER(xfer)->iinfo.sc = sc;
+ usb_init_task(&UXFER(xfer)->abort_task, uhci_timeout_task,
+ xfer);
#ifdef DIAGNOSTIC
UXFER(xfer)->iinfo.isdone = 1;
xfer->busy_free = XFER_BUSY;
@@ -733,6 +741,9 @@ uhci_power(int why, void *v)
if (cmd & UHCI_CMD_RS)
uhci_run(sc, 0); /* in case BIOS has started it */
+ uhci_globalreset(sc);
+ uhci_reset(sc);
+
/* restore saved state */
UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&sc->sc_dma, 0));
UWRITE2(sc, UHCI_FRNUM, sc->sc_saved_frnum);
@@ -1507,7 +1518,6 @@ uhci_timeout(void *addr)
}
/* Execute the abort in a process context. */
- usb_init_task(&uxfer->abort_task, uhci_timeout_task, ii->xfer);
usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task);
}
@@ -1935,7 +1945,7 @@ uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
s = splusb();
xfer->status = status; /* make software ignore it */
usb_uncallout(xfer->timeout_handle, uhci_timeout, xfer);
- usb_transfer_complete(xfer);
+ usb_rem_task(xfer->pipe->device, &UXFER(xfer)->abort_task);
splx(s);
return;
}
@@ -1949,6 +1959,7 @@ uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status)
s = splusb();
xfer->status = status; /* make software ignore it */
usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
+ usb_rem_task(xfer->pipe->device, &UXFER(xfer)->abort_task);
DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
for (std = ii->stdstart; std != NULL; std = std->link.std)
std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
diff --git a/sys/dev/usb/uhci_pci.c b/sys/dev/usb/uhci_pci.c
index f2946ab..a5ba341 100644
--- a/sys/dev/usb/uhci_pci.c
+++ b/sys/dev/usb/uhci_pci.c
@@ -329,8 +329,10 @@ uhci_pci_attach(device_t self)
pci_write_config(self, PCI_LEGSUP, PCI_LEGSUP_USBPIRQDEN, 2);
err = uhci_init(sc);
- if (!err)
+ if (!err) {
+ sc->sc_flags |= UHCI_SCFLG_DONEINIT;
err = device_probe_and_attach(sc->sc_bus.bdev);
+ }
if (err) {
device_printf(self, "USB init failed\n");
@@ -345,22 +347,11 @@ uhci_pci_detach(device_t self)
{
uhci_softc_t *sc = device_get_softc(self);
- /*
- * XXX This function is not yet complete and should not be added
- * method list.
- */
-#if 0
- if uhci_init
- was successful
- we should call something like uhci_deinit
-#endif
+ if (sc->sc_flags & UHCI_SCFLG_DONEINIT) {
+ uhci_detach(sc, 0);
+ sc->sc_flags &= ~UHCI_SCFLG_DONEINIT;
+ }
- /*
- * disable interrupts that might have been switched on in
- * uhci_init.
- */
- if (sc->iot && sc->ioh)
- bus_space_write_2(sc->iot, sc->ioh, UHCI_INTR, 0);
if (sc->irq_res && sc->ih) {
int err = bus_teardown_intr(self, sc->irq_res, sc->ih);
@@ -394,6 +385,7 @@ static device_method_t uhci_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, uhci_pci_probe),
DEVMETHOD(device_attach, uhci_pci_attach),
+ DEVMETHOD(device_detach, uhci_pci_detach),
DEVMETHOD(device_suspend, uhci_pci_suspend),
DEVMETHOD(device_resume, uhci_pci_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
diff --git a/sys/dev/usb/uhcivar.h b/sys/dev/usb/uhcivar.h
index 546dcb1..5670980 100644
--- a/sys/dev/usb/uhcivar.h
+++ b/sys/dev/usb/uhcivar.h
@@ -131,8 +131,11 @@ struct uhci_vframe {
u_int bandwidth; /* max bandwidth used by this frame */
};
+#define UHCI_SCFLG_DONEINIT 0x0001 /* uhci_init() done */
+
typedef struct uhci_softc {
struct usbd_bus sc_bus; /* base device */
+ int sc_flags;
bus_space_tag_t iot;
bus_space_handle_t ioh;
bus_size_t sc_size;
@@ -195,8 +198,8 @@ typedef struct uhci_softc {
usbd_status uhci_init(uhci_softc_t *);
int uhci_intr(void *);
-#if defined(__NetBSD__) || defined(__OpenBSD__)
int uhci_detach(uhci_softc_t *, int);
+#if defined(__NetBSD__) || defined(__OpenBSD__)
int uhci_activate(device_ptr_t, enum devact);
#endif
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 739c33a..d4f6833 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -124,12 +124,13 @@ USB_DECLARE_DRIVER_INIT(uhub,
devclass_t uhubroot_devclass;
Static device_method_t uhubroot_methods[] = {
+ DEVMETHOD(bus_child_detached, uhub_child_detached),
DEVMETHOD(device_probe, uhub_match),
DEVMETHOD(device_attach, uhub_attach),
DEVMETHOD(bus_child_pnpinfo_str, uhub_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, uhub_child_location_str),
- /* detach is not allowed for a root hub */
+ DEVMETHOD(device_detach, uhub_detach),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index d934491..07be320 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -127,6 +127,9 @@ int usb_noexplore = 0;
struct usb_softc {
USBBASEDEVICE sc_dev; /* base device */
+#ifdef __FreeBSD__
+ struct cdev *sc_usbdev; /* /dev/usbN device */
+#endif
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
@@ -162,11 +165,20 @@ struct cdevsw usb_cdevsw = {
#endif
Static void usb_discover(void *);
+#ifdef __FreeBSD__
+Static bus_child_detached_t usb_child_detached;
+#endif
Static void usb_create_event_thread(void *);
Static void usb_event_thread(void *);
Static void usb_task_thread(void *);
Static struct proc *usb_task_thread_proc = NULL;
+#ifdef __FreeBSD__
+Static struct cdev *usb_dev; /* The /dev/usb device. */
+Static int usb_ndevs; /* Number of /dev/usbN devices. */
+Static int usb_taskcreated; /* USB task thread exists. */
+#endif
+
#define USB_MAX_EVENTS 100
struct usb_event_q {
struct usb_event ue;
@@ -185,6 +197,7 @@ Static int usb_get_next_event(struct usb_event *);
Static const char *usbrev_str[] = USBREV_STR;
USB_DECLARE_DRIVER_INIT(usb,
+ DEVMETHOD(bus_child_detached, usb_child_detached),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
DEVMETHOD(device_shutdown, bus_generic_shutdown)
@@ -207,7 +220,6 @@ USB_ATTACH(usb)
#elif defined(__FreeBSD__)
struct usb_softc *sc = device_get_softc(self);
void *aux = device_get_ivars(self);
- static int global_init_done = 0;
#endif
usbd_device_handle dev;
usbd_status err;
@@ -307,13 +319,12 @@ USB_ATTACH(usb)
usb_create_event_thread(sc);
/* The per controller devices (used for usb_discover) */
/* XXX This is redundant now, but old usbd's will want it */
- make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT, GID_OPERATOR,
- 0660, "usb%d", device_get_unit(self));
- if (!global_init_done) {
+ sc->sc_usbdev = make_dev(&usb_cdevsw, device_get_unit(self), UID_ROOT,
+ GID_OPERATOR, 0660, "usb%d", device_get_unit(self));
+ if (usb_ndevs++ == 0) {
/* The device spitting out events */
- make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT, GID_OPERATOR,
- 0660, "usb");
- global_init_done = 1;
+ usb_dev = make_dev(&usb_cdevsw, USB_DEV_MINOR, UID_ROOT,
+ GID_OPERATOR, 0660, "usb");
}
#endif
@@ -324,7 +335,6 @@ void
usb_create_event_thread(void *arg)
{
struct usb_softc *sc = arg;
- static int created = 0;
if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread,
"%s", USBDEVNAME(sc->sc_dev))) {
@@ -332,8 +342,8 @@ usb_create_event_thread(void *arg)
USBDEVNAME(sc->sc_dev));
panic("usb_create_event_thread");
}
- if (!created) {
- created = 1;
+ if (usb_taskcreated == 0) {
+ usb_taskcreated = 1;
TAILQ_INIT(&usb_all_tasks);
if (usb_kthread_create2(usb_task_thread, NULL,
&usb_task_thread_proc, "usbtask")) {
@@ -440,7 +450,7 @@ usb_task_thread(void *arg)
DPRINTF(("usb_task_thread: start\n"));
s = splusb();
- for (;;) {
+ while (usb_ndevs > 0) {
task = TAILQ_FIRST(&usb_all_tasks);
if (task == NULL) {
tsleep(&usb_all_tasks, PWAIT, "usbtsk", 0);
@@ -455,6 +465,13 @@ usb_task_thread(void *arg)
s = splusb();
}
}
+ splx(s);
+
+ usb_taskcreated = 0;
+ wakeup(&usb_taskcreated);
+
+ DPRINTF(("usb_event_thread: exit\n"));
+ kthread_exit(0);
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
@@ -865,11 +882,11 @@ usb_activate(device_ptr_t self, enum devact act)
}
return (rv);
}
+#endif
-int
-usb_detach(device_ptr_t self, int flags)
+USB_DETACH(usb)
{
- struct usb_softc *sc = (struct usb_softc *)self;
+ USB_DETACH_START(usb, sc);
struct usb_event ue;
DPRINTF(("usb_detach: start\n"));
@@ -889,6 +906,17 @@ usb_detach(device_ptr_t self, int flags)
DPRINTF(("usb_detach: event thread dead\n"));
}
+#ifdef __FreeBSD__
+ destroy_dev(sc->sc_usbdev);
+ if (--usb_ndevs == 0) {
+ destroy_dev(usb_dev);
+ usb_dev = NULL;
+ wakeup(&usb_all_tasks);
+ if (tsleep(&usb_taskcreated, PWAIT, "usbtdt", hz * 60))
+ printf("usb task thread didn't die\n");
+ }
+#endif
+
usbd_finish();
#ifdef USB_USE_SOFTINTR
@@ -907,18 +935,17 @@ usb_detach(device_ptr_t self, int flags)
return (0);
}
-#elif defined(__FreeBSD__)
-int
-usb_detach(device_t self)
+
+#if defined(__FreeBSD__)
+Static void
+usb_child_detached(device_t self, device_t child)
{
- DPRINTF(("%s: unload, prevented\n", USBDEVNAME(self)));
+ struct usb_softc *sc = device_get_softc(self);
- return (EINVAL);
+ /* XXX, should check it is the right device. */
+ sc->sc_port.device = NULL;
}
-#endif
-
-#if defined(__FreeBSD__)
DRIVER_MODULE(usb, ohci, usb_driver, usb_devclass, 0, 0);
DRIVER_MODULE(usb, uhci, usb_driver, usb_devclass, 0, 0);
DRIVER_MODULE(usb, ehci, usb_driver, usb_devclass, 0, 0);
OpenPOWER on IntegriCloud