ChangeSet 1.2181.4.47, 2005/03/21 22:36:57-08:00, [EMAIL PROTECTED]
[PATCH] UHCI updates
This is the fifth of five updates to the uhci-hcd driver:
Separate out the part of the driver responsible for scanning the
schedule and doing delayed processing. Put it in a new routine
which can be called as needed (such as when the controller is
suspended) from several places in addition to the usual IRQ
handler.
Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
drivers/usb/host/uhci-hcd.c | 66 ++++----------------------------------------
drivers/usb/host/uhci-hcd.h | 5 ++-
drivers/usb/host/uhci-q.c | 55 ++++++++++++++++++++++++++++++++++++
3 files changed, 65 insertions(+), 61 deletions(-)
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c 2005-03-30 13:35:30 -08:00
+++ b/drivers/usb/host/uhci-hcd.c 2005-03-30 13:35:30 -08:00
@@ -113,18 +113,9 @@
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct urb_priv *up;
unsigned long flags;
- int called_uhci_finish_completion = 0;
spin_lock_irqsave(&uhci->lock, flags);
- uhci_get_current_frame_number(uhci);
-
- if (!list_empty(&uhci->urb_remove_list) &&
- uhci->frame_number + uhci->is_stopped !=
- uhci->urb_remove_age) {
- uhci_remove_pending_urbps(uhci);
- uhci_finish_completion(uhci, NULL);
- called_uhci_finish_completion = 1;
- }
+ uhci_scan_schedule(uhci, NULL);
list_for_each_entry(up, &uhci->urb_list, urb_list) {
struct urb *u = up->urb;
@@ -138,10 +129,6 @@
spin_unlock(&u->lock);
}
- /* Wake up anyone waiting for an URB to complete */
- if (called_uhci_finish_completion)
- wake_up_all(&uhci->waitqh);
-
/* Really disable FSBR */
if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies,
uhci->fsbrtimeout)) {
uhci->fsbrtimeout = 0;
@@ -175,7 +162,6 @@
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long io_addr = uhci->io_addr;
unsigned short status;
- struct urb_priv *urbp, *tmp;
/*
* Read the interrupt status, and write it back to clear the
@@ -205,37 +191,9 @@
uhci->resume_detect = 1;
spin_lock(&uhci->lock);
- uhci_get_current_frame_number(uhci);
-
- if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
- uhci_free_pending_qhs(uhci);
- if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
- uhci_free_pending_tds(uhci);
- if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
- uhci_remove_pending_urbps(uhci);
-
- if (list_empty(&uhci->urb_remove_list) &&
- list_empty(&uhci->td_remove_list) &&
- list_empty(&uhci->qh_remove_list))
- uhci_clear_next_interrupt(uhci);
- else
- uhci_set_next_interrupt(uhci);
-
- /* Walk the list of pending URBs to see which ones completed
- * (must be _safe because uhci_transfer_result() dequeues URBs) */
- list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
- struct urb *urb = urbp->urb;
-
- /* Checks the status and does all of the magic necessary */
- uhci_transfer_result(uhci, urb);
- }
- uhci_finish_completion(uhci, regs);
-
+ uhci_scan_schedule(uhci, regs);
spin_unlock(&uhci->lock);
- /* Wake up anyone waiting for an URB to complete */
- wake_up_all(&uhci->waitqh);
-
return IRQ_HANDLED;
}
@@ -273,6 +231,8 @@
/* FIXME: Wait for the controller to actually stop */
uhci_get_current_frame_number(uhci);
uhci->is_stopped = UHCI_IS_STOPPED;
+
+ uhci_scan_schedule(uhci, NULL);
}
static void wakeup_hc(struct uhci_hcd *uhci)
@@ -746,26 +706,11 @@
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
del_timer_sync(&uhci->stall_timer);
-
- /*
- * At this point, we're guaranteed that no new connects can be made
- * to this bus since there are no more parents
- */
-
reset_hc(uhci);
spin_lock_irq(&uhci->lock);
- uhci_free_pending_qhs(uhci);
- uhci_free_pending_tds(uhci);
- uhci_remove_pending_urbps(uhci);
- uhci_finish_completion(uhci, NULL);
-
- uhci_free_pending_qhs(uhci);
- uhci_free_pending_tds(uhci);
+ uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock);
-
- /* Wake up anyone waiting for an URB to complete */
- wake_up_all(&uhci->waitqh);
release_uhci(uhci);
}
@@ -784,6 +729,7 @@
spin_unlock_irq(&uhci->lock);
reset_hc(uhci);
spin_lock_irq(&uhci->lock);
+ uhci_scan_schedule(uhci, NULL);
}
spin_unlock_irq(&uhci->lock);
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h 2005-03-30 13:35:30 -08:00
+++ b/drivers/usb/host/uhci-hcd.h 2005-03-30 13:35:30 -08:00
@@ -365,10 +365,13 @@
enum uhci_state state; /* FIXME: needs a spinlock */
unsigned long state_end; /* Time of next transition */
- int resume_detect; /* Need a Global Resume */
unsigned int frame_number; /* As of last check */
unsigned int is_stopped;
#define UHCI_IS_STOPPED 9999 /* Larger than a frame
# */
+
+ unsigned int scan_in_progress:1; /* Schedule scan is running */
+ unsigned int need_rescan:1; /* Redo the schedule scan */
+ unsigned int resume_detect:1; /* Need a Global Resume */
/* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
diff -Nru a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
--- a/drivers/usb/host/uhci-q.c 2005-03-30 13:35:30 -08:00
+++ b/drivers/usb/host/uhci-q.c 2005-03-30 13:35:30 -08:00
@@ -1482,3 +1482,58 @@
/* Splice the urb_remove_list onto the end of the complete_list */
list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev);
}
+
+/* Process events in the schedule, but only in one thread at a time */
+static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
+{
+ struct urb_priv *urbp, *tmp;
+
+ /* Don't allow re-entrant calls */
+ if (uhci->scan_in_progress) {
+ uhci->need_rescan = 1;
+ return;
+ }
+ uhci->scan_in_progress = 1;
+ rescan:
+ uhci->need_rescan = 0;
+
+ uhci_get_current_frame_number(uhci);
+
+ if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
+ uhci_free_pending_qhs(uhci);
+ if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age)
+ uhci_free_pending_tds(uhci);
+ if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age)
+ uhci_remove_pending_urbps(uhci);
+
+ /* Walk the list of pending URBs to see which ones completed
+ * (must be _safe because uhci_transfer_result() dequeues URBs) */
+ list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) {
+ struct urb *urb = urbp->urb;
+
+ /* Checks the status and does all of the magic necessary */
+ uhci_transfer_result(uhci, urb);
+ }
+ uhci_finish_completion(uhci, regs);
+
+ /* If the controller is stopped, we can finish these off right now */
+ if (uhci->is_stopped) {
+ uhci_free_pending_qhs(uhci);
+ uhci_free_pending_tds(uhci);
+ uhci_remove_pending_urbps(uhci);
+ }
+
+ if (uhci->need_rescan)
+ goto rescan;
+ uhci->scan_in_progress = 0;
+
+ if (list_empty(&uhci->urb_remove_list) &&
+ list_empty(&uhci->td_remove_list) &&
+ list_empty(&uhci->qh_remove_list))
+ uhci_clear_next_interrupt(uhci);
+ else
+ uhci_set_next_interrupt(uhci);
+
+ /* Wake up anyone waiting for an URB to complete */
+ wake_up_all(&uhci->waitqh);
+}
-------------------------------------------------------
This SF.net email is sponsored by Demarc:
A global provider of Threat Management Solutions.
Download our HomeAdmin security software for free today!
http://www.demarc.com/info/Sentarus/hamr30
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel