[PATCH 2/7] USB: UHCI: Allow dynamic assignment of bus specific functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxx>
---
 drivers/usb/host/uhci-hcd.c |   89 +++++++++++++++++++++++++++++++++---------
 drivers/usb/host/uhci-hcd.h |   10 +++++
 2 files changed, 80 insertions(+), 19 deletions(-)

diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 0b7e6e1..e36d6c4 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -143,13 +143,23 @@ static void finish_reset(struct uhci_hcd *uhci)
 }
 
 /*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+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);
+	if (uhci->reset_hc)
+		uhci->reset_hc(uhci);
 	finish_reset(uhci);
 	uhci->dead = 1;
 
@@ -158,23 +168,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->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 +217,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 +254,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 +287,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)
@@ -558,6 +598,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.
 	 */
@@ -848,7 +898,8 @@ 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);
+		if (uhci->reset_hc)
+			uhci->reset_hc(uhci);
 		finish_reset(uhci);
 	}
 
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index f86db61..5694379 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 */
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux