Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 95803
b: refs/heads/master
c: d8f12ab
h: refs/heads/master
i:
  95801: fa2fe3d
  95799: d57b43b
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed May 2, 2008
1 parent 74d1c3e commit 1120fb0
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1b7b61c5d4071b9a25f6a9aae6f0a1e0efdbb2ae
refs/heads/master: d8f12ab5d984761726e638a4222299a9fc516233
74 changes: 58 additions & 16 deletions trunk/drivers/usb/host/uhci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
return 0;
}

static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
{
int port;
const char *sys_info;
Expand All @@ -261,27 +261,60 @@ __releases(uhci->lock)
__acquires(uhci->lock)
{
int auto_stop;
int int_enable, egsm_enable;
int int_enable, egsm_enable, wakeup_enable;
struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;

auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
dev_dbg(&rhdev->dev, "%s%s\n", __func__,
(auto_stop ? " (auto-stop)" : ""));

/* Enable resume-detect interrupts if they work.
* Then enter Global Suspend mode if _it_ works, still configured.
/* Start off by assuming Resume-Detect interrupts and EGSM work
* and that remote wakeups should be enabled.
*/
egsm_enable = USBCMD_EGSM;
uhci->working_RD = 1;
uhci->RD_enable = 1;
int_enable = USBINTR_RESUME;
if (remote_wakeup_is_broken(uhci))
egsm_enable = 0;
if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
wakeup_enable = 1;

/* In auto-stop mode wakeups must always be detected, but
* Resume-Detect interrupts may be prohibited. (In the absence
* of CONFIG_PM, they are always disallowed.)
*/
if (auto_stop) {
if (!device_may_wakeup(&rhdev->dev))
int_enable = 0;

/* In bus-suspend mode wakeups may be disabled, but if they are
* allowed then so are Resume-Detect interrupts.
*/
} else {
#ifdef CONFIG_PM
(!auto_stop && !rhdev->do_remote_wakeup) ||
if (!rhdev->do_remote_wakeup)
wakeup_enable = 0;
#endif
(auto_stop && !device_may_wakeup(&rhdev->dev)))
uhci->working_RD = int_enable = 0;
}

/* EGSM causes the root hub to echo a 'K' signal (resume) out any
* port which requests a remote wakeup. According to the USB spec,
* every hub is supposed to do this. But if we are ignoring
* remote-wakeup requests anyway then there's no point to it.
* We also shouldn't enable EGSM if it's broken.
*/
if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
egsm_enable = 0;

/* If we're ignoring wakeup events then there's no reason to
* enable Resume-Detect interrupts. We also shouldn't enable
* them if they are broken or disallowed.
*
* This logic may lead us to enabling RD but not EGSM. The UHCI
* spec foolishly says that RD works only when EGSM is on, but
* there's no harm in enabling it anyway -- perhaps some chips
* will implement it!
*/
if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
!int_enable)
uhci->RD_enable = int_enable = 0;

outw(int_enable, uhci->io_addr + USBINTR);
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
Expand All @@ -308,7 +341,11 @@ __acquires(uhci->lock)

uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->poll_rh = !int_enable;

/* If interrupts don't work and remote wakeup is enabled then
* the suspended root hub needs to be polled.
*/
uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);

uhci_scan_schedule(uhci);
uhci_fsbr_off(uhci);
Expand Down Expand Up @@ -344,9 +381,12 @@ __acquires(uhci->lock)
* for 20 ms.
*/
if (uhci->rh_state == UHCI_RH_SUSPENDED) {
unsigned egsm;

/* Keep EGSM on if it was set before */
egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
uhci->rh_state = UHCI_RH_RESUMING;
outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
uhci->io_addr + USBCMD);
outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
Expand Down Expand Up @@ -801,8 +841,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)

spin_unlock_irq(&uhci->lock);

if (!uhci->working_RD) {
/* Suspended root hub needs to be polled */
/* If interrupts don't work and remote wakeup is enabled then
* the suspended root hub needs to be polled.
*/
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd);
}
Expand Down
5 changes: 3 additions & 2 deletions trunk/drivers/usb/host/uhci-hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -400,8 +400,9 @@ struct uhci_hcd {
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int dead:1; /* Controller has died */
unsigned int working_RD:1; /* Suspended root hub doesn't
need to be polled */
unsigned int RD_enable:1; /* Suspended root hub with
Resume-Detect interrupts
enabled */
unsigned int is_initialized:1; /* Data structure is usable */
unsigned int fsbr_is_on:1; /* FSBR is turned on */
unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */
Expand Down

0 comments on commit 1120fb0

Please sign in to comment.