mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-13 16:50:05 +00:00
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>
This commit is contained in:
parent
dfeca7a875
commit
e7652e1ebc
@ -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)
|
|||||||
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)
|
|||||||
++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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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 {
|
|||||||
|
|
||||||
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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user