PERFORCE change 130957 for review
Hans Petter Selasky
hselasky at FreeBSD.org
Sat Dec 15 09:08:13 PST 2007
http://perforce.freebsd.org/chv.cgi?CH=130957
Change 130957 by hselasky at hselasky_laptop001 on 2007/12/15 17:07:50
This commit is required for USB device side support.
o This commit adds automatic context detection to
"usb_callback_wrapper()", so that you can call the
"usb_callback_wrapper()" from almost everywhere.
This leads to a lot of cleanup related to calling
callbacks in the EHCI, OHCI and UHCI drivers.
o Optimized "uhci_interrupt()" a little bit.
o The interrupt list where USB transfers are queued
has been moved to "struct usbd_bus" so that we can
factor out some code.
o Allow all "usbd_bus_mem_xxx" functions to be passed
a NULL callback pointer.
Affected files ...
.. //depot/projects/usb/src/sys/dev/usb/ehci.c#62 edit
.. //depot/projects/usb/src/sys/dev/usb/ehci.h#25 edit
.. //depot/projects/usb/src/sys/dev/usb/ohci.c#51 edit
.. //depot/projects/usb/src/sys/dev/usb/ohci.h#21 edit
.. //depot/projects/usb/src/sys/dev/usb/uhci.c#52 edit
.. //depot/projects/usb/src/sys/dev/usb/uhci.h#21 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#70 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#75 edit
.. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#70 edit
Differences ...
==== //depot/projects/usb/src/sys/dev/usb/ehci.c#62 (text+ko) ====
@@ -79,7 +79,7 @@
printf x ; } } while (0)
#define DPRINTFN(n,x) do { if (ehcidebug > (n)) { printf("%s: ", __FUNCTION__); \
printf x ; } } while (0)
-int ehcidebug = 0;
+static int ehcidebug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci");
SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW,
@@ -105,11 +105,11 @@
extern struct usbd_pipe_methods ehci_root_intr_methods;
static usbd_config_td_command_t ehci_root_ctrl_task;
-static void ehci_root_ctrl_task_td(struct ehci_softc *sc, struct thread *ctd);
static void ehci_do_poll(struct usbd_bus *bus);
+static void ehci_root_ctrl_poll(struct ehci_softc *sc);
static usbd_std_root_transfer_func_t ehci_root_intr_done;
-static usbd_std_root_transfer_func_t ehci_root_ctrl_task_td_sub;
+static usbd_std_root_transfer_func_t ehci_root_ctrl_done;
struct ehci_std_temp {
struct usbd_page_cache *pc;
@@ -213,8 +213,6 @@
DPRINTF(("start\n"));
- LIST_INIT(&sc->sc_interrupt_list_head);
-
usb_callout_init_mtx(&sc->sc_tmo_pcd, &sc->sc_bus.mtx,
CALLOUT_RETURNUNLOCKED);
@@ -1280,18 +1278,12 @@
* Else: USB transfer is finished
*------------------------------------------------------------------------*/
static uint8_t
-ehci_check_transfer(struct usbd_xfer *xfer, struct thread *ctd)
+ehci_check_transfer(struct usbd_xfer *xfer)
{
struct usbd_pipe_methods *methods = xfer->pipe->methods;
uint32_t status;
- if (xfer->usb_thread != ctd) {
- /*
- * cannot call this transfer back due to locking !
- */
- goto done;
- }
DPRINTFN(12, ("xfer=%p checking transfer\n", xfer));
if (methods == &ehci_device_isoc_fs_methods) {
@@ -1402,57 +1394,48 @@
/* acknowledge any PCD interrupt */
EOWRITE4(sc, EHCI_USBSTS, EHCI_STS_PCD);
- if (usbd_std_root_transfer(&(sc->sc_root_intr), NULL,
- &ehci_root_intr_done)) {
- mtx_unlock(&(sc->sc_bus.mtx));
- }
+ usbd_std_root_transfer(&(sc->sc_root_intr),
+ &ehci_root_intr_done);
+
+ mtx_unlock(&(sc->sc_bus.mtx));
return;
}
static void
-ehci_interrupt_td(ehci_softc_t *sc, struct thread *ctd)
+ehci_interrupt_poll(ehci_softc_t *sc)
{
- enum {
- FINISH_LIST_MAX = 16};
-
- struct usbd_xfer *xlist[FINISH_LIST_MAX + 1];
- struct usbd_xfer **xptr = xlist;
struct usbd_xfer *xfer;
- struct thread *td;
- uint32_t status;
- uint8_t need_repeat = 0;
- td = ctd; /* default value */
-
- mtx_lock(&sc->sc_bus.mtx);
-
- /*
- * It can happen that an interrupt will be delivered to
- * us before the device has been fully attached and the
- * softc struct has been configured. Usually this happens
- * when kldloading the USB support as a module after the
- * system has been booted. If we detect this condition,
- * we need to squelch the unwanted interrupts until we're
- * ready for them.
- */
- if (sc->sc_bus.bdev == NULL) {
- goto done;
- }
- if (ctd) {
+ LIST_FOREACH(xfer, &sc->sc_bus.intr_list_head, interrupt_list) {
/*
- * the poll thread should not read any status registers that
- * will clear interrupts!
+ * check if transfer is transferred
*/
- goto repeat;
+ if (ehci_check_transfer(xfer)) {
+ /* queue callback for execution */
+ usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK);
+ }
}
- td = curthread; /* NULL is not a valid thread */
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * ehci_interrupt - EHCI interrupt handler
+ *
+ * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler,
+ * hence the interrupt handler will be setup before "sc->sc_bus.bdev"
+ * is present !
+ *------------------------------------------------------------------------*/
+void
+ehci_interrupt(ehci_softc_t *sc)
+{
+ uint32_t status;
+
+ mtx_lock(&sc->sc_bus.mtx);
- DPRINTFN(15, ("%s: real interrupt\n",
- device_get_nameunit(sc->sc_bus.bdev)));
+ DPRINTFN(15, ("real interrupt\n"));
#ifdef USB_DEBUG
if (ehcidebug > 15) {
- DPRINTF(("%s\n", device_get_nameunit(sc->sc_bus.bdev)));
ehci_dump_regs(sc);
}
#endif
@@ -1474,8 +1457,8 @@
wakeup(&sc->sc_async_p_last);
}
if (status & EHCI_STS_HSE) {
- device_printf(sc->sc_bus.bdev, "unrecoverable error, "
- "controller halted\n");
+ printf("%s: unrecoverable error, "
+ "controller halted\n", __FUNCTION__);
#ifdef USB_DEBUG
ehci_dump_regs(sc);
ehci_dump_isoc(sc);
@@ -1489,13 +1472,12 @@
sc->sc_eintrs &= ~EHCI_STS_PCD;
EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
- if (!usbd_std_root_transfer(&(sc->sc_root_intr), ctd,
- &ehci_root_intr_done)) {
- mtx_lock(&(sc->sc_bus.mtx));
- }
+ usbd_std_root_transfer(&(sc->sc_root_intr),
+ &ehci_root_intr_done);
+
/* do not allow RHSC interrupts > 1 per second */
usb_callout_reset(&sc->sc_tmo_pcd, hz,
- (void *)(void *)ehci_pcd_enable, sc);
+ (void *)&ehci_pcd_enable, sc);
}
status &= ~(EHCI_STS_INT | EHCI_STS_ERRINT | EHCI_STS_PCD | EHCI_STS_IAA);
@@ -1503,69 +1485,24 @@
/* block unprocessed interrupts */
sc->sc_eintrs &= ~status;
EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
- device_printf(sc->sc_bus.bdev, "blocking intrs 0x%x\n",
- status);
+ printf("%s: blocking interrupts 0x%x\n", __FUNCTION__, status);
}
-repeat:
- LIST_FOREACH(xfer, &sc->sc_interrupt_list_head, interrupt_list) {
- /*
- * check if transfer is transferred
- */
- if (ehci_check_transfer(xfer, ctd)) {
- /* queue callback */
-
- *(xptr++) = xfer;
+ /* poll all the USB transfers */
+ ehci_interrupt_poll(sc);
- xfer->usb_thread = td;
- xfer->usb_root->memory_refcount++;
-
- /* check queue length */
- if (xptr >= &xlist[FINISH_LIST_MAX]) {
- need_repeat = 1;
- break;
- }
- }
- }
-
done:
mtx_unlock(&sc->sc_bus.mtx);
-
- /* zero terminate the callback list */
- *(xptr) = NULL;
-
- usbd_do_callback(xlist, td);
-
- if (need_repeat) {
- xptr = xlist;
-
- need_repeat = 0;
-
- mtx_lock(&sc->sc_bus.mtx);
-
- goto repeat;
- }
return;
}
-void
-ehci_interrupt(ehci_softc_t *sc)
-{
- ehci_interrupt_td(sc, NULL);
- return;
-}
-
/*
* called when a request does not complete
*/
static void
ehci_timeout(struct usbd_xfer *xfer)
{
- struct thread *td;
- struct usbd_xfer *xlist[2];
ehci_softc_t *sc = xfer->usb_sc;
- td = curthread;
-
DPRINTF(("xfer=%p\n", xfer));
mtx_assert(&sc->sc_bus.mtx, MA_OWNED);
@@ -1573,17 +1510,11 @@
/* transfer is transferred */
ehci_device_done(xfer, USBD_TIMEOUT);
- /* queue callback */
- xlist[0] = xfer;
- xlist[1] = NULL;
-
- xfer->usb_thread = td;
- xfer->usb_root->memory_refcount++;
+ /* queue callback for execution */
+ usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK);
mtx_unlock(&sc->sc_bus.mtx);
- usbd_do_callback(xlist, td);
-
return;
}
@@ -1591,29 +1522,15 @@
ehci_do_poll(struct usbd_bus *bus)
{
struct ehci_softc *sc = EHCI_BUS2SC(bus);
- struct thread *ctd = curthread;
- ehci_interrupt_td(sc, ctd);
mtx_lock(&(sc->sc_bus.mtx));
- ehci_root_ctrl_task_td(sc, ctd);
+ ehci_interrupt_poll(sc);
+ ehci_root_ctrl_poll(sc);
mtx_unlock(&(sc->sc_bus.mtx));
return;
}
-#define ehci_add_interrupt_info(sc, xfer) \
- LIST_INSERT_HEAD(&(sc)->sc_interrupt_list_head, (xfer), interrupt_list)
-
static void
-ehci_remove_interrupt_info(struct usbd_xfer *xfer)
-{
- if ((xfer)->interrupt_list.le_prev) {
- LIST_REMOVE((xfer), interrupt_list);
- (xfer)->interrupt_list.le_prev = NULL;
- }
- return;
-}
-
-static void
ehci_setup_standard_chain_sub(struct ehci_std_temp *temp)
{
struct usbd_page_search buf_res;
@@ -2227,12 +2144,6 @@
xfer->td_transfer_first = NULL;
xfer->td_transfer_last = NULL;
}
- /* stop timeout */
- usb_callout_stop(&xfer->timeout_handle);
-
- /* remove interrupt info (if any) */
- ehci_remove_interrupt_info(xfer);
-
if ((methods != &ehci_root_ctrl_methods) &&
(methods != &ehci_root_intr_methods)) {
@@ -2329,7 +2240,7 @@
ehci_setup_standard_chain(xfer, &sc->sc_async_p_last);
/**/
- ehci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
if (xfer->timeout && (!xfer->flags.use_polling)) {
usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout),
@@ -2379,7 +2290,7 @@
ehci_setup_standard_chain(xfer, &sc->sc_async_p_last);
/**/
- ehci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
if (xfer->timeout && (!xfer->flags.use_polling)) {
usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout),
@@ -2485,7 +2396,7 @@
ehci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]);
/**/
- ehci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
if (xfer->timeout && (!xfer->flags.use_polling)) {
usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout),
@@ -2741,7 +2652,7 @@
(EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
/**/
- ehci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
/*
* enqueue transfer (so that it can be aborted through pipe abort)
@@ -3020,7 +2931,7 @@
(EHCI_VIRTUAL_FRAMELIST_COUNT - 1);
/**/
- ehci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
/*
* enqueue transfer (so that it can be aborted through pipe abort)
@@ -3192,12 +3103,12 @@
ehci_root_ctrl_task(struct ehci_softc *sc,
struct ehci_config_copy *cc, uint16_t refcount)
{
- ehci_root_ctrl_task_td(sc, NULL);
+ ehci_root_ctrl_poll(sc);
return;
}
static void
-ehci_root_ctrl_task_td_sub(struct usbd_xfer *xfer,
+ehci_root_ctrl_done(struct usbd_xfer *xfer,
struct usbd_std_root_transfer *std)
{
struct ehci_softc *sc = xfer->usb_sc;
@@ -3592,12 +3503,10 @@
}
static void
-ehci_root_ctrl_task_td(struct ehci_softc *sc, struct thread *ctd)
+ehci_root_ctrl_poll(struct ehci_softc *sc)
{
- if (!usbd_std_root_transfer(&(sc->sc_root_ctrl), ctd,
- &ehci_root_ctrl_task_td_sub)) {
- mtx_lock(&sc->sc_bus.mtx);
- }
+ usbd_std_root_transfer(&(sc->sc_root_ctrl),
+ &ehci_root_ctrl_done);
return;
}
==== //depot/projects/usb/src/sys/dev/usb/ehci.h#25 (text+ko) ====
@@ -443,7 +443,6 @@
struct usbd_bus sc_bus; /* base device */
struct usbd_config_td sc_config_td;
struct usb_callout sc_tmo_pcd;
- LIST_HEAD(, usbd_xfer) sc_interrupt_list_head;
union ehci_hub_desc sc_hub_desc;
struct usbd_std_root_transfer sc_root_ctrl;
struct usbd_std_root_transfer sc_root_intr;
==== //depot/projects/usb/src/sys/dev/usb/ohci.c#51 (text+ko) ====
@@ -84,7 +84,7 @@
#undef DPRINTFN
#define DPRINTF(x) do { if (ohcidebug) { printf("%s: ", __FUNCTION__); printf x ; } } while (0)
#define DPRINTFN(n,x) do { if (ohcidebug > (n)) { printf("%s: ", __FUNCTION__); printf x ; } } while (0)
-int ohcidebug = 0;
+static int ohcidebug = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci");
SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW,
@@ -121,12 +121,12 @@
extern struct usbd_pipe_methods ohci_root_intr_methods;
static usbd_config_td_command_t ohci_root_ctrl_task;
-static void ohci_root_ctrl_task_td(struct ohci_softc *sc, struct thread *ctd);
+static void ohci_root_ctrl_poll(struct ohci_softc *sc);
static void ohci_do_poll(struct usbd_bus *bus);
static void ohci_device_done(struct usbd_xfer *xfer, usbd_status_t error);
static usbd_std_root_transfer_func_t ohci_root_intr_done;
-static usbd_std_root_transfer_func_t ohci_root_ctrl_task_td_sub;
+static usbd_std_root_transfer_func_t ohci_root_ctrl_done;
struct ohci_std_temp {
struct usbd_page_cache *pc;
@@ -412,8 +412,6 @@
usbd_bus_mem_flush_all(&(sc->sc_bus), &ohci_iterate_hw_softc);
- LIST_INIT(&sc->sc_interrupt_list_head);
-
/* set up the bus struct */
sc->sc_bus.methods = &ohci_bus_methods;
@@ -1055,19 +1053,13 @@
* Else: USB transfer is finished
*------------------------------------------------------------------------*/
static uint8_t
-ohci_check_transfer(struct usbd_xfer *xfer, struct thread *ctd)
+ohci_check_transfer(struct usbd_xfer *xfer)
{
ohci_ed_t *ed = xfer->qh_start;
uint32_t ed_flags;
uint32_t ed_headp;
uint32_t ed_tailp;
- if (xfer->usb_thread != ctd) {
- /*
- * cannot call this transfer back due to locking !
- */
- return (0);
- }
DPRINTFN(12, ("xfer=%p checking transfer\n", xfer));
usbd_pc_cpu_invalidate(ed->page_cache);
@@ -1118,54 +1110,52 @@
/* acknowledge any RHSC interrupt */
OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC);
- if (usbd_std_root_transfer(&(sc->sc_root_intr), NULL,
- &ohci_root_intr_done)) {
- mtx_unlock(&(sc->sc_bus.mtx));
- }
+ usbd_std_root_transfer(&(sc->sc_root_intr),
+ &ohci_root_intr_done);
+
+ mtx_unlock(&(sc->sc_bus.mtx));
return;
}
static void
-ohci_interrupt_td(ohci_softc_t *sc, struct thread *ctd)
+ohci_interrupt_poll(ohci_softc_t *sc)
{
- enum {
- FINISH_LIST_MAX = 16,
- };
+ struct usbd_xfer *xfer;
+
+ LIST_FOREACH(xfer, &(sc->sc_bus.intr_list_head), interrupt_list) {
+ /*
+ * check if transfer is transferred
+ */
+ if (ohci_check_transfer(xfer)) {
+ /* queue callback for execution */
+ usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK);
+ }
+ }
+ return;
+}
- struct usbd_xfer *xlist[FINISH_LIST_MAX + 1];
- struct usbd_xfer **xptr = xlist;
+/*------------------------------------------------------------------------*
+ * ohci_interrupt - OHCI interrupt handler
+ *
+ * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler,
+ * hence the interrupt handler will be setup before "sc->sc_bus.bdev"
+ * is present !
+ *------------------------------------------------------------------------*/
+void
+ohci_interrupt(ohci_softc_t *sc)
+{
struct ohci_hcca *hcca;
- struct usbd_xfer *xfer;
- struct thread *td;
uint32_t status;
uint32_t done;
- uint8_t need_repeat = 0;
- td = ctd; /* default value */
-
mtx_lock(&sc->sc_bus.mtx);
- if (sc->sc_bus.bdev == NULL) {
- /* too early interrupt */
- goto done;
- }
- if (ctd) {
- /*
- * the poll thread should not read any status registers that
- * will clear interrupts!
- */
- goto repeat;
- }
- td = curthread; /* NULL is not a valid thread */
-
hcca = ohci_get_hcca(sc);
- DPRINTFN(15, ("%s: real interrupt\n",
- device_get_nameunit(sc->sc_bus.bdev)));
+ DPRINTFN(15, ("real interrupt\n"));
#ifdef USB_DEBUG
if (ohcidebug > 15) {
- DPRINTF(("%s:\n", device_get_nameunit(sc->sc_bus.bdev)));
ohci_dumpregs(sc);
}
#endif
@@ -1221,12 +1211,12 @@
}
#endif
if (status & OHCI_RD) {
- device_printf(sc->sc_bus.bdev, "resume detect\n");
+ printf("%s: resume detect\n", __FUNCTION__);
/* XXX process resume detect */
}
if (status & OHCI_UE) {
- device_printf(sc->sc_bus.bdev, "unrecoverable error, "
- "controller halted\n");
+ printf("%s: unrecoverable error, "
+ "controller halted\n", __FUNCTION__);
OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
/* XXX what else */
}
@@ -1238,13 +1228,12 @@
sc->sc_eintrs &= ~OHCI_RHSC;
OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC);
- if (!usbd_std_root_transfer(&(sc->sc_root_intr), ctd,
- &ohci_root_intr_done)) {
- mtx_lock(&(sc->sc_bus.mtx));
- }
+ usbd_std_root_transfer(&(sc->sc_root_intr),
+ &ohci_root_intr_done);
+
/* do not allow RHSC interrupts > 1 per second */
usb_callout_reset(&sc->sc_tmo_rhsc, hz,
- (void *)(void *)ohci_rhsc_enable, sc);
+ (void *)&ohci_rhsc_enable, sc);
}
}
status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO);
@@ -1252,73 +1241,25 @@
/* Block unprocessed interrupts. XXX */
OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status);
sc->sc_eintrs &= ~status;
- device_printf(sc->sc_bus.bdev,
- "blocking intrs 0x%x\n", status);
+ printf("%s: blocking intrs 0x%x\n",
+ __FUNCTION__, status);
}
- /*
- * when the host controller interrupts because a transfer
- * is completed, all active transfers are checked!
- */
+ /* poll all the USB transfers */
+ ohci_interrupt_poll(sc);
-repeat:
- LIST_FOREACH(xfer, &sc->sc_interrupt_list_head, interrupt_list) {
- /*
- * check if transfer is transferred
- */
- if (ohci_check_transfer(xfer, ctd)) {
- /* queue callback */
-
- *(xptr++) = xfer;
-
- xfer->usb_thread = td;
- xfer->usb_root->memory_refcount++;
-
- /* check queue length */
- if (xptr >= &xlist[FINISH_LIST_MAX]) {
- need_repeat = 1;
- break;
- }
- }
- }
-
done:
mtx_unlock(&sc->sc_bus.mtx);
-
- /* zero terminate the callback list */
- *(xptr) = NULL;
-
- usbd_do_callback(xlist, td);
-
- if (need_repeat) {
- xptr = xlist;
-
- need_repeat = 0;
- mtx_lock(&sc->sc_bus.mtx);
-
- goto repeat;
- }
return;
}
-void
-ohci_interrupt(ohci_softc_t *sc)
-{
- ohci_interrupt_td(sc, NULL);
- return;
-}
-
/*
* called when a request does not complete
*/
static void
ohci_timeout(struct usbd_xfer *xfer)
{
- struct thread *td;
- struct usbd_xfer *xlist[2];
ohci_softc_t *sc = xfer->usb_sc;
- td = curthread;
-
DPRINTF(("xfer=%p\n", xfer));
mtx_assert(&sc->sc_bus.mtx, MA_OWNED);
@@ -1326,17 +1267,11 @@
/* transfer is transferred */
ohci_device_done(xfer, USBD_TIMEOUT);
- /* queue callback */
- xlist[0] = xfer;
- xlist[1] = NULL;
-
- xfer->usb_thread = td;
- xfer->usb_root->memory_refcount++;
+ /* queue callback for execution */
+ usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK);
mtx_unlock(&sc->sc_bus.mtx);
- usbd_do_callback(xlist, td);
-
return;
}
@@ -1344,28 +1279,14 @@
ohci_do_poll(struct usbd_bus *bus)
{
struct ohci_softc *sc = OHCI_BUS2SC(bus);
- struct thread *ctd = curthread;
- ohci_interrupt_td(sc, ctd);
mtx_lock(&(sc->sc_bus.mtx));
- ohci_root_ctrl_task_td(sc, ctd);
+ ohci_interrupt_poll(sc);
+ ohci_root_ctrl_poll(sc);
mtx_unlock(&(sc->sc_bus.mtx));
return;
}
-#define ohci_add_interrupt_info(sc, xfer) \
- LIST_INSERT_HEAD(&(sc)->sc_interrupt_list_head, (xfer), interrupt_list)
-
-static void
-ohci_remove_interrupt_info(struct usbd_xfer *xfer)
-{
- if ((xfer)->interrupt_list.le_prev) {
- LIST_REMOVE((xfer), interrupt_list);
- (xfer)->interrupt_list.le_prev = NULL;
- }
- return;
-}
-
static void
ohci_setup_standard_chain_sub(struct ohci_std_temp *temp)
{
@@ -1765,12 +1686,6 @@
xfer->td_transfer_first = NULL;
xfer->td_transfer_last = NULL;
- /* stop timeout */
- usb_callout_stop(&xfer->timeout_handle);
-
- /* remove interrupt info */
- ohci_remove_interrupt_info(xfer);
-
if ((methods != &ohci_root_ctrl_methods) &&
(methods != &ohci_root_intr_methods)) {
@@ -1820,7 +1735,7 @@
ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last);
/**/
- ohci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
if (xfer->timeout && (!(xfer->flags.use_polling))) {
usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout),
@@ -1870,7 +1785,7 @@
ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last);
/**/
- ohci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
if (xfer->timeout && (!(xfer->flags.use_polling))) {
usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout),
@@ -1952,7 +1867,7 @@
ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]);
/**/
- ohci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
if (xfer->timeout && (!(xfer->flags.use_polling))) {
usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout),
@@ -2151,7 +2066,7 @@
OHCI_APPEND_QH(ed, td->itd_self, sc->sc_isoc_p_last);
/**/
- ohci_add_interrupt_info(sc, xfer);
+ usbd_transfer_intr_enqueue(xfer);
/*
* enqueue transfer (so that it can be aborted through pipe abort)
@@ -2296,12 +2211,12 @@
ohci_root_ctrl_task(struct ohci_softc *sc,
struct ohci_config_copy *cc, uint16_t refcount)
{
- ohci_root_ctrl_task_td(sc, NULL);
+ ohci_root_ctrl_poll(sc);
return;
}
static void
-ohci_root_ctrl_task_td_sub(struct usbd_xfer *xfer,
+ohci_root_ctrl_done(struct usbd_xfer *xfer,
struct usbd_std_root_transfer *std)
{
ohci_softc_t *sc = xfer->usb_sc;
@@ -2604,12 +2519,10 @@
}
static void
-ohci_root_ctrl_task_td(struct ohci_softc *sc, struct thread *ctd)
+ohci_root_ctrl_poll(struct ohci_softc *sc)
{
- if (!usbd_std_root_transfer(&(sc->sc_root_ctrl), ctd,
- &ohci_root_ctrl_task_td_sub)) {
- mtx_lock(&sc->sc_bus.mtx);
- }
+ usbd_std_root_transfer(&(sc->sc_root_ctrl),
+ &ohci_root_ctrl_done);
return;
}
==== //depot/projects/usb/src/sys/dev/usb/ohci.h#21 (text+ko) ====
@@ -320,7 +320,6 @@
struct usbd_bus sc_bus; /* base device */
struct usbd_config_td sc_config_td;
struct usb_callout sc_tmo_rhsc;
- LIST_HEAD(, usbd_xfer) sc_interrupt_list_head;
union ohci_hub_desc sc_hub_desc;
struct usbd_std_root_transfer sc_root_ctrl;
struct usbd_std_root_transfer sc_root_intr;
==== //depot/projects/usb/src/sys/dev/usb/uhci.c#52 (text+ko) ====
@@ -87,8 +87,8 @@
#undef DPRINTFN
#define DPRINTF(x) do { if (uhcidebug) { printf("%s: ", __FUNCTION__); printf x ; } } while (0)
#define DPRINTFN(n,x) do { if (uhcidebug > (n)) { printf("%s: ", __FUNCTION__); printf x ; } } while (0)
-int uhcidebug = 0;
-int uhcinoloop = 0;
+static int uhcidebug = 0;
+static int uhcinoloop = 0;
SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci");
SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW,
@@ -158,7 +158,7 @@
extern struct usbd_pipe_methods uhci_root_intr_methods;
static usbd_config_td_command_t uhci_root_ctrl_task;
-static void uhci_root_ctrl_task_td(struct uhci_softc *sc, struct thread *ctd);
+static void uhci_root_ctrl_poll(struct uhci_softc *sc);
static void uhci_do_poll(struct usbd_bus *bus);
static void uhci_device_done(struct usbd_xfer *xfer, usbd_status_t error);
@@ -618,8 +618,6 @@
usbd_bus_mem_flush_all(&(sc->sc_bus), &uhci_iterate_hw_softc);
- LIST_INIT(&sc->sc_interrupt_list_head);
-
/* set up the bus struct */
sc->sc_bus.methods = &uhci_bus_methods;
@@ -852,20 +850,6 @@
return;
}
-#if 0
-static void
-uhci_dump_iis(struct uhci_softc *sc)
-{
- struct usbd_xfer *xfer;
-
- printf("interrupt list:\n");
- LIST_FOREACH(xfer, &sc->sc_interrupt_list_head, interrupt_list) {
- usbd_dump_xfer(xfer);
- }
- return;
-}
-
-#endif
#endif
/*
@@ -1341,18 +1325,12 @@
* Else: USB transfer is finished
*------------------------------------------------------------------------*/
static uint8_t
-uhci_check_transfer(struct usbd_xfer *xfer, struct thread *ctd)
+uhci_check_transfer(struct usbd_xfer *xfer)
{
uint32_t status;
uint32_t token;
uhci_td_t *td;
- if (xfer->usb_thread != ctd) {
- /*
- * cannot call this transfer back due to locking !
- */
- goto done;
- }
DPRINTFN(15, ("xfer=%p checking transfer\n", xfer));
if (xfer->pipe->methods == &uhci_device_isoc_methods) {
@@ -1436,54 +1414,40 @@
}
static void
-uhci_interrupt_td(uhci_softc_t *sc, struct thread *ctd)
+uhci_interrupt_poll(uhci_softc_t *sc)
{
- enum {
- FINISH_LIST_MAX = 16};
-
- struct usbd_xfer *xlist[FINISH_LIST_MAX + 1];
- struct usbd_xfer **xptr = xlist;
struct usbd_xfer *xfer;
- struct thread *td;
- uint32_t status;
- uint8_t need_repeat = 0;
- td = ctd; /* default value */
-
- mtx_lock(&sc->sc_bus.mtx);
-
- /*
- * It can happen that an interrupt will be delivered to
- * us before the device has been fully attached and the
- * softc struct has been configured. Usually this happens
- * when kldloading the USB support as a module after the
- * system has been booted. If we detect this condition,
- * we need to squelch the unwanted interrupts until we're
- * ready for them.
- */
- if (sc->sc_bus.bdev == NULL) { /* XXX */
-#if 0
- UWRITE2(sc, UHCI_STS, 0xFFFF); /* ack pending interrupts */
- uhci_reset(sc); /* stop the controller */
- UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */
-#endif
- goto done;
- }
- if (ctd) {
+ LIST_FOREACH(xfer, &(sc->sc_bus.intr_list_head), interrupt_list) {
/*
- * the poll thread should not read any status registers that
- * will clear interrupts!
+ * check if transfer is transferred
*/
- goto repeat;
+ if (uhci_check_transfer(xfer)) {
+ /* queue callback for execution */
+ usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK);
+ }
}
- td = curthread; /* NULL is not a valid thread */
+ return;
+}
+
+/*------------------------------------------------------------------------*
+ * uhci_interrupt - UHCI interrupt handler
+ *
+ * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler,
+ * hence the interrupt handler will be setup before "sc->sc_bus.bdev"
+ * is present !
+ *------------------------------------------------------------------------*/
+void
+uhci_interrupt(uhci_softc_t *sc)
+{
+ uint32_t status;
+
+ mtx_lock(&sc->sc_bus.mtx);
- DPRINTFN(15, ("%s: real interrupt\n",
- device_get_nameunit(sc->sc_bus.bdev)));
+ DPRINTFN(15, ("real interrupt\n"));
#ifdef USB_DEBUG
if (uhcidebug > 15) {
- DPRINTF(("%s\n", device_get_nameunit(sc->sc_bus.bdev)));
uhci_dumpregs(sc);
}
#endif
@@ -1492,27 +1456,31 @@
/* the interrupt was not for us */
goto done;
}
- if (status & UHCI_STS_RD) {
+ if (status & (UHCI_STS_RD | UHCI_STS_HSE |
+ UHCI_STS_HCPE | UHCI_STS_HCH)) {
+
+ if (status & UHCI_STS_RD) {
#ifdef USB_DEBUG
- device_printf(sc->sc_bus.bdev,
- "resume detect\n");
+ printf("%s: resume detect\n",
+ __FUNCTION__);
#endif
- }
- if (status & UHCI_STS_HSE) {
- device_printf(sc->sc_bus.bdev,
- "host system error\n");
- }
- if (status & UHCI_STS_HCPE) {
- device_printf(sc->sc_bus.bdev,
- "host controller process error\n");
- }
- if (status & UHCI_STS_HCH) {
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list