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.
This commit is contained in:
parent
dc5c8e8f74
commit
78620e321f
@ -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__)
|
||||
|
@ -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));
|
||||
@ -310,12 +317,29 @@ 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));
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user