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
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to