summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjoe <joe@FreeBSD.org>2002-04-02 09:49:36 +0000
committerjoe <joe@FreeBSD.org>2002-04-02 09:49:36 +0000
commit2104113695511c03369543a79653dd5c3cf5f15d (patch)
tree1090a50a5fde6e5d19b418a59ea4d27dffe43271 /sys
parentb4aab89cbc8252f1064803ddc1dba28b2be03b49 (diff)
downloadFreeBSD-src-2104113695511c03369543a79653dd5c3cf5f15d.zip
FreeBSD-src-2104113695511c03369543a79653dd5c3cf5f15d.tar.gz
MFNetBSD: uhub.c (1.49), usb.c (1.51), usbdi.h (1.48), usbdivar.h (1.63)
date: 2001/01/21 19:00:06; author: augustss; Change the operation of the USB event thread. Before it only performed USB device discovery, now it can also perform (short) tasks for device drivers that need a process context, but don't have one. This is not pretty, but better than using busy-wait in an interrupt context.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/uhub.c5
-rw-r--r--sys/dev/usb/usb.c80
-rw-r--r--sys/dev/usb/usbdi.h17
-rw-r--r--sys/dev/usb/usbdivar.h4
4 files changed, 76 insertions, 30 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 36c700f..d358590 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhub.c,v 1.48 2000/12/29 01:24:56 augustss Exp $ */
+/* $NetBSD: uhub.c,v 1.49 2001/01/21 19:00:06 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -592,7 +592,8 @@ uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
if (status == USBD_STALLED)
usbd_clear_endpoint_stall_async(sc->sc_ipipe);
else if (status == USBD_NORMAL_COMPLETION)
- usb_needs_explore(sc->sc_hub->bus);
+ usb_needs_explore(sc->sc_hub);
+
}
#if defined(__FreeBSD__)
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index d7cfcd5..fec7dc5 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usb.c,v 1.49 2001/01/21 02:39:53 augustss Exp $ */
+/* $NetBSD: usb.c,v 1.51 2001/01/21 19:00:06 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -117,8 +117,11 @@ struct usb_softc {
usbd_bus_handle sc_bus; /* USB controller */
struct usbd_port sc_port; /* dummy port for root hub */
+ SIMPLEQ_HEAD(, usb_task) sc_tasks;
struct proc *sc_event_thread;
+ struct usb_task sc_exp_task;
+
char sc_dying;
};
@@ -151,7 +154,7 @@ struct cdevsw usb_cdevsw = {
};
#endif
-Static usbd_status usb_discover(void *);
+Static void usb_discover(void *);
Static void usb_create_event_thread(void *);
Static void usb_event_thread(void *);
@@ -210,6 +213,10 @@ USB_ATTACH(usb)
sc->sc_bus = aux;
sc->sc_bus->usbctl = sc;
sc->sc_port.power = USB_MAX_POWER;
+ SIMPLEQ_INIT(&sc->sc_tasks);
+
+ sc->sc_exp_task.fun = usb_discover;
+ sc->sc_exp_task.arg = sc;
#if defined(__FreeBSD__)
printf("%s", USBDEVNAME(sc->sc_dev));
@@ -311,11 +318,28 @@ usb_create_event_thread(void *arg)
}
void
+usb_add_task(usbd_device_handle dev, struct usb_task *task)
+{
+ struct usb_softc *sc = dev->bus->usbctl;
+ int s;
+
+ s = splusb();
+ if (!task->onqueue) {
+ DPRINTFN(2,("usb_add_task: sc=%p task=%p\n", sc, task));
+ SIMPLEQ_INSERT_TAIL(&sc->sc_tasks, task, next);
+ task->onqueue = 1;
+ } else
+ DPRINTFN(3,("usb_add_task: sc=%p task=%p on q\n", sc, task));
+ wakeup(&sc->sc_tasks);
+ splx(s);
+}
+
+void
usb_event_thread(void *arg)
{
struct usb_softc *sc = arg;
- int to;
- int first = 1;
+ struct usb_task *task;
+ int s;
#ifdef __FreeBSD__
mtx_lock(&Giant);
@@ -325,23 +349,24 @@ usb_event_thread(void *arg)
/* Make sure first discover does something. */
sc->sc_bus->needs_explore = 1;
+ usb_discover(sc);
+ config_pending_decr();
while (!sc->sc_dying) {
-#ifdef USB_DEBUG
- if (usb_noexplore < 2)
-#endif
- usb_discover(sc);
- if (first) {
- config_pending_decr();
- first = 0;
+ s = splusb();
+ task = SIMPLEQ_FIRST(&sc->sc_tasks);
+ if (task == NULL) {
+ tsleep(&sc->sc_tasks, PWAIT, "usbevt", 0);
+ task = SIMPLEQ_FIRST(&sc->sc_tasks);
}
- to = hz * 60;
-#ifdef USB_DEBUG
- if (usb_noexplore)
- to = 0;
-#endif
- (void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt", to);
- DPRINTFN(2,("usb_event_thread: woke up\n"));
+ DPRINTFN(2,("usb_event_thread: woke up task=%p\n", task));
+ if (task != NULL && !sc->sc_dying) {
+ SIMPLEQ_REMOVE_HEAD(&sc->sc_tasks, task, next);
+ task->onqueue = 0;
+ splx(s);
+ task->fun(task->arg);
+ } else
+ splx(s);
}
sc->sc_event_thread = NULL;
@@ -587,7 +612,7 @@ usbpoll(dev_t dev, int events, usb_proc_ptr p)
}
/* Explore device tree from the root. */
-usbd_status
+Static void
usb_discover(void *v)
{
struct usb_softc *sc = v;
@@ -597,6 +622,12 @@ usb_discover(void *v)
int s;
#endif
+ DPRINTFN(2,("usb_discover\n"));
+#ifdef USB_DEBUG
+ if (usb_noexplore > 1)
+ return;
+#endif
+
/*
* We need mutual exclusion while traversing the device tree,
* but this is guaranteed since this function is only called
@@ -618,15 +649,14 @@ usb_discover(void *v)
#if defined(__FreeBSD__)
splx(s);
#endif
-
- return (USBD_NORMAL_COMPLETION);
}
void
-usb_needs_explore(usbd_bus_handle bus)
+usb_needs_explore(usbd_device_handle dev)
{
- bus->needs_explore = 1;
- wakeup(&bus->needs_explore);
+ DPRINTFN(2,("usb_needs_explore\n"));
+ dev->bus->needs_explore = 1;
+ usb_add_task(dev, &dev->bus->usbctl->sc_exp_task);
}
/* Called at splusb() */
@@ -776,7 +806,7 @@ usb_detach(device_ptr_t self, int flags)
/* Kill off event thread. */
if (sc->sc_event_thread) {
- wakeup(&sc->sc_bus->needs_explore);
+ wakeup(&sc->sc_tasks);
if (tsleep(sc, PWAIT, "usbdet", hz * 60))
printf("%s: event thread didn't die\n",
USBDEVNAME(sc->sc_dev));
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 64f4644..f1824c5 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdi.h,v 1.47 2001/01/21 02:39:53 augustss Exp $ */
+/* $NetBSD: usbdi.h,v 1.48 2001/01/21 19:00:06 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -177,6 +177,21 @@ usb_endpoint_descriptor_t *usbd_get_endpoint_descriptor
usbd_status usbd_reload_device_desc(usbd_device_handle);
+/*
+ * The usb_task structs form a queue of things to run in the USB event
+ * thread. Normally this is just device discovery when a connect/disconnect
+ * has been detected. But it may also be used by drivers that need to
+ * perform (short) tasks that must have a process context.
+ */
+struct usb_task {
+ SIMPLEQ_ENTRY(usb_task) next;
+ void (*fun)(void *);
+ void *arg;
+ char onqueue;
+};
+
+void usb_add_task(usbd_device_handle dev, struct usb_task *task);
+
struct usb_devno {
u_int16_t ud_vendor;
u_int16_t ud_product;
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 0fe761b..bc39792 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdivar.h,v 1.62 2001/01/21 02:39:53 augustss Exp $ */
+/* $NetBSD: usbdivar.h,v 1.63 2001/01/21 19:00:06 augustss Exp $ */
/* $FreeBSD$ */
/*
@@ -249,7 +249,7 @@ void usb_transfer_complete(usbd_xfer_handle xfer);
void usb_disconnect_port(struct usbd_port *up, device_ptr_t);
/* Routines from usb.c */
-void usb_needs_explore(usbd_bus_handle);
+void usb_needs_explore(usbd_device_handle);
void usb_schedsoftintr(struct usbd_bus *);
/*
OpenPOWER on IntegriCloud