diff options
author | joe <joe@FreeBSD.org> | 2002-04-02 09:49:36 +0000 |
---|---|---|
committer | joe <joe@FreeBSD.org> | 2002-04-02 09:49:36 +0000 |
commit | 2104113695511c03369543a79653dd5c3cf5f15d (patch) | |
tree | 1090a50a5fde6e5d19b418a59ea4d27dffe43271 /sys | |
parent | b4aab89cbc8252f1064803ddc1dba28b2be03b49 (diff) | |
download | FreeBSD-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.c | 5 | ||||
-rw-r--r-- | sys/dev/usb/usb.c | 80 | ||||
-rw-r--r-- | sys/dev/usb/usbdi.h | 17 | ||||
-rw-r--r-- | sys/dev/usb/usbdivar.h | 4 |
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 *); /* |