summaryrefslogtreecommitdiff
path: root/sys/dev/usb/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/usb.c')
-rw-r--r--sys/dev/usb/usb.c71
1 files changed, 49 insertions, 22 deletions
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index d934491eb1f8..07be320209ca 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);