Commit e7652e1e authored by Jan Andersson's avatar Jan Andersson Committed by Greg Kroah-Hartman

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: default avatarJan Andersson <jan@gaisler.com>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dfeca7a8
...@@ -142,6 +142,15 @@ static void finish_reset(struct uhci_hcd *uhci) ...@@ -142,6 +142,15 @@ static void finish_reset(struct uhci_hcd *uhci)
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); 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 * Last rites for a defunct/nonfunctional controller
* or one we don't want to use any more. * or one we don't want to use any more.
...@@ -149,7 +158,7 @@ static void finish_reset(struct uhci_hcd *uhci) ...@@ -149,7 +158,7 @@ static void finish_reset(struct uhci_hcd *uhci)
static void uhci_hc_died(struct uhci_hcd *uhci) static void uhci_hc_died(struct uhci_hcd *uhci)
{ {
uhci_get_current_frame_number(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); finish_reset(uhci);
uhci->dead = 1; uhci->dead = 1;
...@@ -157,6 +166,18 @@ static void uhci_hc_died(struct uhci_hcd *uhci) ...@@ -157,6 +166,18 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
++uhci->frame_number; ++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 * Initialize a controller that was newly discovered or has lost power
* or otherwise been reset while it was suspended. In none of these cases * 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) ...@@ -164,17 +185,27 @@ static void uhci_hc_died(struct uhci_hcd *uhci)
*/ */
static void check_and_reset_hc(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); 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. * Store the basic register settings needed by the controller.
*/ */
static void configure_hc(struct uhci_hcd *uhci) 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 */ /* Set the frame length to the default: 1 ms exactly */
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
...@@ -185,24 +216,15 @@ static void configure_hc(struct uhci_hcd *uhci) ...@@ -185,24 +216,15 @@ static void configure_hc(struct uhci_hcd *uhci)
outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER, outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
uhci->io_addr + USBFRNUM); uhci->io_addr + USBFRNUM);
/* Enable PIRQ */ /* perform any arch/bus specific configuration */
pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT); if (uhci->configure_hc)
uhci->configure_hc(uhci);
/* Disable platform-specific non-PME# wakeup */
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
pci_write_config_byte(pdev, USBRES_INTEL, 0);
} }
static int uhci_pci_resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
{ {
int port; 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) { switch (to_pci_dev(uhci_dev(uhci))->vendor) {
default: default:
break; break;
...@@ -231,7 +253,18 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) ...@@ -231,7 +253,18 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
return 0; 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; int port;
const char *sys_info; const char *sys_info;
...@@ -253,6 +286,12 @@ static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) ...@@ -253,6 +286,12 @@ static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
return 0; 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) static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
__releases(uhci->lock) __releases(uhci->lock)
__acquires(uhci->lock) __acquires(uhci->lock)
...@@ -557,6 +596,16 @@ static int uhci_init(struct usb_hcd *hcd) ...@@ -557,6 +596,16 @@ static int uhci_init(struct usb_hcd *hcd)
if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP) if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP)
uhci->wait_for_hp = 1; 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 /* Kick BIOS off this hardware and reset if the controller
* isn't already safely quiescent. * isn't already safely quiescent.
*/ */
...@@ -847,7 +896,7 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) ...@@ -847,7 +896,7 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
/* Make sure resume from hibernation re-enumerates everything */ /* Make sure resume from hibernation re-enumerates everything */
if (hibernated) { if (hibernated) {
uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); uhci->reset_hc(uhci);
finish_reset(uhci); finish_reset(uhci);
} }
......
...@@ -433,6 +433,16 @@ struct uhci_hcd { ...@@ -433,6 +433,16 @@ struct uhci_hcd {
int total_load; /* Sum of array values */ int total_load; /* Sum of array values */
short load[MAX_PHASE]; /* Periodic allocations */ 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 */ /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment