From 4d8c7e278116822a79a8e6f3289597805631b781 Mon Sep 17 00:00:00 2001 From: iedowse Date: Mon, 2 Aug 2004 15:37:35 +0000 Subject: Make the USB subsystem unloadable and detachable, though currently a significant amount of memory may be leaked each time a host controller is detached. --- sys/dev/usb/ehci.c | 22 +++++++++------- sys/dev/usb/ehci_pci.c | 45 +++++++++++++++++++++++++++----- sys/dev/usb/ehcivar.h | 6 ++++- sys/dev/usb/ohci.c | 16 +++++++++--- sys/dev/usb/ohci_pci.c | 20 ++++++-------- sys/dev/usb/ohcivar.h | 5 +++- sys/dev/usb/uhci.c | 17 +++++++++--- sys/dev/usb/uhci_pci.c | 24 ++++++----------- sys/dev/usb/uhcivar.h | 5 +++- sys/dev/usb/uhub.c | 3 ++- sys/dev/usb/usb.c | 71 ++++++++++++++++++++++++++++++++++---------------- 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); -- cgit v1.1