summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorJan Andersson <jan@gaisler.com>2011-05-06 12:00:13 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-06 18:23:59 -0700
commite7652e1ebc0f5e07929067ece14ca869dad20dd6 (patch)
treecbdca7e57d94be0be8fcee5f6f412eec937188ef /drivers/usb
parentdfeca7a8750296a7d065d45257b3cd86aadc3fb9 (diff)
downloadlinux-e7652e1ebc0f5e07929067ece14ca869dad20dd6.tar.gz
linux-e7652e1ebc0f5e07929067ece14ca869dad20dd6.tar.bz2
linux-e7652e1ebc0f5e07929067ece14ca869dad20dd6.zip
USB: UHCI: Allow dynamic assignment of bus specific functions
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/uhci-hcd.c87
-rw-r--r--drivers/usb/host/uhci-hcd.h10
2 files changed, 78 insertions, 19 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 214851a6244f..683e87e49a03 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -143,13 +143,22 @@ static void finish_reset(struct uhci_hcd *uhci)
}
/*
+ * 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.
*/
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;
@@ -158,23 +167,45 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
}
/*
+ * 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
* can we be sure of its previous state.
*/
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);
}
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index f86db61cf085..569437954578 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -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 */