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.
This commit is contained in:
augustss 2001-01-21 19:00:06 +00:00
parent d8f68f3949
commit df20cb2972
4 changed files with 77 additions and 31 deletions

View File

@ -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: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
/*
@ -568,7 +568,7 @@ uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
if (status != USBD_NORMAL_COMPLETION)
usbd_clear_endpoint_stall_async(sc->sc_ipipe);
usb_needs_explore(sc->sc_hub->bus);
usb_needs_explore(sc->sc_hub);
}
#if defined(__FreeBSD__)

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb.c,v 1.50 2001/01/21 16:55:11 augustss Exp $ */
/* $NetBSD: usb.c,v 1.51 2001/01/21 19:00:06 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -93,14 +93,17 @@ 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;
};
cdev_decl(usb);
Static usbd_status usb_discover(struct usb_softc *);
Static void usb_discover(void *);
Static void usb_create_event_thread(void *);
Static void usb_event_thread(void *);
@ -143,6 +146,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;
usbrev = sc->sc_bus->usbrev;
printf(": USB revision %s", usbrev_str[usbrev]);
@ -221,34 +228,52 @@ 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 first = 1;
struct usb_task *task;
int s;
DPRINTF(("usb_event_thread: start\n"));
/* 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);
}
#ifdef USB_DEBUG
(void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
usb_noexplore ? 0 : hz * 60);
#else
(void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
hz * 60);
#endif
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;
@ -482,9 +507,16 @@ usbpoll(dev_t dev, int events, struct proc *p)
}
/* Explore device tree from the root. */
usbd_status
usb_discover(struct usb_softc *sc)
Static void
usb_discover(void *v)
{
struct usb_softc *sc = v;
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
@ -494,15 +526,14 @@ usb_discover(struct usb_softc *sc)
sc->sc_bus->needs_explore = 0;
sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
}
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() */
@ -628,7 +659,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));

View File

@ -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: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */
/*
@ -178,6 +178,21 @@ usbd_status usbd_reload_device_desc(usbd_device_handle);
int usbd_ratecheck(struct timeval *last);
/*
* 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);
/* NetBSD attachment information */
/* Attach data */

View File

@ -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: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
/*
@ -248,7 +248,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 *);
/*