Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 3660
b: refs/heads/master
c: 4daaa87
h: refs/heads/master
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Jun 27, 2005
1 parent 82ecb2c commit 8ec78f0
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 22 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: a8bed8b6be75bc5a46aa599ab360d5f1db291c8f
refs/heads/master: 4daaa87c8f19c5f1978470e9e91b74d9e0fb0f8e
86 changes: 65 additions & 21 deletions trunk/drivers/usb/host/uhci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,13 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
* (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
* (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
* people who decided that they want to do the same thing in a
* completely different way.
*
* WARNING! The USB documentation is downright evil. Most of it
* is just crap, written by a committee. You're better off ignoring
* most of it, the important stuff is:
* - the low-level protocol (fairly simple but lots of small details)
* - working around the horridness of the rest
*/

#include <linux/config.h>
Expand Down Expand Up @@ -146,6 +141,15 @@ static void reset_hc(struct uhci_hcd *uhci)
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
}

/*
* Last rites for a defunct/nonfunctional controller
*/
static void hc_died(struct uhci_hcd *uhci)
{
reset_hc(uhci);
uhci->hc_inaccessible = 1;
}

/*
* Initialize a controller that was newly discovered or has just been
* resumed. In either case we can't be sure of its previous state.
Expand Down Expand Up @@ -287,6 +291,8 @@ __acquires(uhci->lock)
spin_unlock_irq(&uhci->lock);
msleep(1);
spin_lock_irq(&uhci->lock);
if (uhci->hc_inaccessible) /* Died */
return;
}
if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
Expand Down Expand Up @@ -335,6 +341,8 @@ __acquires(uhci->lock)
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
if (uhci->hc_inaccessible) /* Died */
return;

/* End Global Resume and wait for EOP to be sent */
outw(USBCMD_CF, uhci->io_addr + USBCMD);
Expand Down Expand Up @@ -387,9 +395,11 @@ static void stall_callback(unsigned long _uhci)
check_fsbr(uhci);

/* Poll for and perform state transitions */
rh_state_transitions(uhci);
if (uhci->suspended_ports && !uhci->hc_inaccessible)
uhci_check_ports(uhci);
if (!uhci->hc_inaccessible) {
rh_state_transitions(uhci);
if (uhci->suspended_ports)
uhci_check_ports(uhci);
}

restart_timer(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
Expand All @@ -399,6 +409,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned short status;
unsigned long flags;

/*
* Read the interrupt status, and write it back to clear the
Expand All @@ -417,20 +428,26 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
if (status & USBSTS_HCPE)
dev_err(uhci_dev(uhci), "host controller process "
"error, something bad happened!\n");
if ((status & USBSTS_HCH) &&
uhci->rh_state >= UHCI_RH_RUNNING) {
dev_err(uhci_dev(uhci), "host controller halted, "
if (status & USBSTS_HCH) {
spin_lock_irqsave(&uhci->lock, flags);
if (uhci->rh_state >= UHCI_RH_RUNNING) {
dev_err(uhci_dev(uhci),
"host controller halted, "
"very bad!\n");
/* FIXME: Reset the controller, fix the offending TD */
hc_died(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
return IRQ_HANDLED;
}
spin_unlock_irqrestore(&uhci->lock, flags);
}
}

if (status & USBSTS_RD)
uhci->resume_detect = 1;

spin_lock(&uhci->lock);
spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci, regs);
spin_unlock(&uhci->lock);
spin_unlock_irqrestore(&uhci->lock, flags);

return IRQ_HANDLED;
}
Expand Down Expand Up @@ -525,10 +542,15 @@ static int uhci_start(struct usb_hcd *hcd)
struct dentry *dentry;

io_size = (unsigned) hcd->rsrc_len;
if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
hcd->can_wakeup = 1; /* Assume it supports PME# */

dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
dentry = debugfs_create_file(hcd->self.bus_name,
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
&uhci_debug_operations);
if (!dentry) {
dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
dev_err(uhci_dev(uhci),
"couldn't create uhci debugfs entry\n");
retval = -ENOMEM;
goto err_create_debug_entry;
}
Expand Down Expand Up @@ -765,34 +787,53 @@ static int uhci_rh_suspend(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd);

spin_lock_irq(&uhci->lock);
suspend_rh(uhci, UHCI_RH_SUSPENDED);
if (!uhci->hc_inaccessible) /* Not dead */
suspend_rh(uhci, UHCI_RH_SUSPENDED);
spin_unlock_irq(&uhci->lock);
return 0;
}

static int uhci_rh_resume(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int rc = 0;

spin_lock_irq(&uhci->lock);
wakeup_rh(uhci);
if (uhci->hc_inaccessible) {
if (uhci->rh_state == UHCI_RH_SUSPENDED) {
dev_warn(uhci_dev(uhci), "HC isn't running!\n");
rc = -ENODEV;
}
/* Otherwise the HC is dead */
} else
wakeup_rh(uhci);
spin_unlock_irq(&uhci->lock);
return 0;
return rc;
}

static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int rc = 0;

dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);

spin_lock_irq(&uhci->lock);
if (uhci->hc_inaccessible) /* Dead or already suspended */
goto done;

#ifndef CONFIG_USB_SUSPEND
/* Otherwise this would never happen */
suspend_rh(uhci, UHCI_RH_SUSPENDED);
#endif

if (uhci->rh_state > UHCI_RH_SUSPENDED) {
dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
hcd->state = HC_STATE_RUNNING;
rc = -EBUSY;
goto done;
};

/* All PCI host controllers are required to disable IRQ generation
* at the source, so we must turn off PIRQ.
*/
Expand All @@ -801,8 +842,9 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)

/* FIXME: Enable non-PME# remote wakeup? */

done:
spin_unlock_irq(&uhci->lock);
return 0;
return rc;
}

static int uhci_resume(struct usb_hcd *hcd)
Expand All @@ -811,6 +853,8 @@ static int uhci_resume(struct usb_hcd *hcd)

dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);

if (uhci->rh_state == UHCI_RH_RESET) /* Dead */
return 0;
spin_lock_irq(&uhci->lock);

/* FIXME: Disable non-PME# remote wakeup? */
Expand Down

0 comments on commit 8ec78f0

Please sign in to comment.