]> Pileus Git - ~andy/linux/commitdiff
USB: UHCI: Allow dynamic assignment of bus specific functions
authorJan Andersson <jan@gaisler.com>
Fri, 6 May 2011 10:00:13 +0000 (12:00 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sat, 7 May 2011 01:23:59 +0000 (18:23 -0700)
This patch is part of a series that extend the UHCI HCD to support
non-PCI controllers.

This patch changes calls to uhci_reset_hc, uhci_check_and_reset_hc,
configure_hc, resume_detect_interrupts_are_broken and
global_suspend_mode_is_broken so that they are made through pointers
in the uhci hcd struct. This will allow these functions to be replaced
with bus/arch specific functions.

Signed-off-by: Jan Andersson <jan@gaisler.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h

index 214851a6244f2b0ab5d520d001fd2f565fc08a94..683e87e49a034622fed42e2350831036185bac51 100644 (file)
@@ -142,6 +142,15 @@ static void finish_reset(struct uhci_hcd *uhci)
        clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
 }
 
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+static void uhci_pci_reset_hc(struct uhci_hcd *uhci)
+{
+       uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
+}
+
 /*
  * Last rites for a defunct/nonfunctional controller
  * or one we don't want to use any more.
@@ -149,7 +158,7 @@ static void finish_reset(struct uhci_hcd *uhci)
 static void uhci_hc_died(struct uhci_hcd *uhci)
 {
        uhci_get_current_frame_number(uhci);
-       uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
+       uhci->reset_hc(uhci);
        finish_reset(uhci);
        uhci->dead = 1;
 
@@ -157,6 +166,18 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
        ++uhci->frame_number;
 }
 
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed.  In either case we can't be sure of its previous state.
+ *
+ * Returns: 1 if the controller was reset, 0 otherwise.
+ */
+static int uhci_pci_check_and_reset_hc(struct uhci_hcd *uhci)
+{
+       return uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)),
+                               uhci->io_addr);
+}
+
 /*
  * Initialize a controller that was newly discovered or has lost power
  * or otherwise been reset while it was suspended.  In none of these cases
@@ -164,17 +185,27 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
  */
 static void check_and_reset_hc(struct uhci_hcd *uhci)
 {
-       if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr))
+       if (uhci->check_and_reset_hc(uhci))
                finish_reset(uhci);
 }
 
+static void uhci_pci_configure_hc(struct uhci_hcd *uhci)
+{
+       struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
+
+       /* Enable PIRQ */
+       pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+       /* Disable platform-specific non-PME# wakeup */
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+               pci_write_config_byte(pdev, USBRES_INTEL, 0);
+}
+
 /*
  * Store the basic register settings needed by the controller.
  */
 static void configure_hc(struct uhci_hcd *uhci)
 {
-       struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
-
        /* Set the frame length to the default: 1 ms exactly */
        outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 
@@ -185,24 +216,15 @@ static void configure_hc(struct uhci_hcd *uhci)
        outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
                        uhci->io_addr + USBFRNUM);
 
-       /* Enable PIRQ */
-       pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-       /* Disable platform-specific non-PME# wakeup */
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL)
-               pci_write_config_byte(pdev, USBRES_INTEL, 0);
+       /* perform any arch/bus specific configuration */
+       if (uhci->configure_hc)
+               uhci->configure_hc(uhci);
 }
 
-
-static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
+static int uhci_pci_resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
 {
        int port;
 
-       /* If we have to ignore overcurrent events then almost by definition
-        * we can't depend on resume-detect interrupts. */
-       if (ignore_oc)
-               return 1;
-
        switch (to_pci_dev(uhci_dev(uhci))->vendor) {
            default:
                break;
@@ -231,7 +253,18 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
        return 0;
 }
 
-static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
+static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
+{
+       /* If we have to ignore overcurrent events then almost by definition
+        * we can't depend on resume-detect interrupts. */
+       if (ignore_oc)
+               return 1;
+
+       return uhci->resume_detect_interrupts_are_broken ?
+               uhci->resume_detect_interrupts_are_broken(uhci) : 0;
+}
+
+static int uhci_pci_global_suspend_mode_is_broken(struct uhci_hcd *uhci)
 {
        int port;
        const char *sys_info;
@@ -253,6 +286,12 @@ static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
        return 0;
 }
 
+static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
+{
+       return uhci->global_suspend_mode_is_broken ?
+               uhci->global_suspend_mode_is_broken(uhci) : 0;
+}
+
 static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
 __releases(uhci->lock)
 __acquires(uhci->lock)
@@ -557,6 +596,16 @@ static int uhci_init(struct usb_hcd *hcd)
        if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP)
                uhci->wait_for_hp = 1;
 
+       /* Set up pointers to PCI-specific functions */
+       uhci->reset_hc = uhci_pci_reset_hc;
+       uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc;
+       uhci->configure_hc = uhci_pci_configure_hc;
+       uhci->resume_detect_interrupts_are_broken =
+               uhci_pci_resume_detect_interrupts_are_broken;
+       uhci->global_suspend_mode_is_broken =
+               uhci_pci_global_suspend_mode_is_broken;
+
+
        /* Kick BIOS off this hardware and reset if the controller
         * isn't already safely quiescent.
         */
@@ -847,7 +896,7 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 
        /* Make sure resume from hibernation re-enumerates everything */
        if (hibernated) {
-               uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
+               uhci->reset_hc(uhci);
                finish_reset(uhci);
        }
 
index f86db61cf085668f442299292f6ee4c927b758c7..569437954578e0fd31f2114a8e2961b2408ed398 100644 (file)
@@ -433,6 +433,16 @@ struct uhci_hcd {
 
        int total_load;                         /* Sum of array values */
        short load[MAX_PHASE];                  /* Periodic allocations */
+
+       /* Reset host controller */
+       void    (*reset_hc) (struct uhci_hcd *uhci);
+       int     (*check_and_reset_hc) (struct uhci_hcd *uhci);
+       /* configure_hc should perform arch specific settings, if needed */
+       void    (*configure_hc) (struct uhci_hcd *uhci);
+       /* Check for broken resume detect interrupts */
+       int     (*resume_detect_interrupts_are_broken) (struct uhci_hcd *uhci);
+       /* Check for broken global suspend */
+       int     (*global_suspend_mode_is_broken) (struct uhci_hcd *uhci);
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */