Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 3661
b: refs/heads/master
c: 6c1b445
h: refs/heads/master
i:
  3659: 82ecb2c
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Jun 27, 2005
1 parent 8ec78f0 commit c2a53a1
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 61 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: 4daaa87c8f19c5f1978470e9e91b74d9e0fb0f8e
refs/heads/master: 6c1b445c226dd82d0961725dec8051b95003723a
70 changes: 23 additions & 47 deletions trunk/drivers/usb/host/uhci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ static char *errbuf;

static kmem_cache_t *uhci_up_cachep; /* urb_priv */

static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);

/* If a transfer is still active after this much time, turn off FSBR */
Expand Down Expand Up @@ -133,12 +135,12 @@ static void reset_hc(struct uhci_hcd *uhci)
outw(0, uhci->io_addr + USBINTR);
outw(0, uhci->io_addr + USBCMD);

uhci->resume_detect = 0;
uhci->port_c_suspend = uhci->suspended_ports =
uhci->resuming_ports = 0;
uhci->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
uhci_to_hcd(uhci)->poll_rh = 0;
}

/*
Expand All @@ -148,6 +150,7 @@ static void hc_died(struct uhci_hcd *uhci)
{
reset_hc(uhci);
uhci->hc_inaccessible = 1;
del_timer(&uhci->stall_timer);
}

/*
Expand Down Expand Up @@ -302,14 +305,14 @@ __acquires(uhci->lock)

uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci->resume_detect = 0;
del_timer(&uhci->stall_timer);
uhci_to_hcd(uhci)->poll_rh = !int_enable;

uhci_scan_schedule(uhci, NULL);
}

static void start_rh(struct uhci_hcd *uhci)
{
uhci->rh_state = UHCI_RH_RUNNING;
uhci->is_stopped = 0;
smp_wmb();

Expand All @@ -320,6 +323,9 @@ static void start_rh(struct uhci_hcd *uhci)
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
uhci->io_addr + USBINTR);
mb();
uhci->rh_state = UHCI_RH_RUNNING;
uhci_to_hcd(uhci)->poll_rh = 1;
restart_timer(uhci);
}

static void wakeup_rh(struct uhci_hcd *uhci)
Expand Down Expand Up @@ -353,36 +359,9 @@ __acquires(uhci->lock)
}

start_rh(uhci);
}

static void rh_state_transitions(struct uhci_hcd *uhci)
{
switch (uhci->rh_state) {
case UHCI_RH_RUNNING:
/* are any devices attached? */
if (!any_ports_active(uhci)) {
uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
uhci->auto_stop_time = jiffies + HZ;
}
break;

case UHCI_RH_RUNNING_NODEVS:
/* auto-stop if nothing connected for 1 second */
if (any_ports_active(uhci))
uhci->rh_state = UHCI_RH_RUNNING;
else if (time_after_eq(jiffies, uhci->auto_stop_time))
suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
break;

case UHCI_RH_AUTO_STOPPED:
/* wakeup if requested by a device */
if (uhci->resume_detect)
wakeup_rh(uhci);
break;

default:
break;
}
/* Restart root hub polling */
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
}

static void stall_callback(unsigned long _uhci)
Expand All @@ -394,14 +373,8 @@ static void stall_callback(unsigned long _uhci)
uhci_scan_schedule(uhci, NULL);
check_fsbr(uhci);

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

restart_timer(uhci);
if (!uhci->is_stopped)
restart_timer(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
}

Expand Down Expand Up @@ -443,7 +416,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
}

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

spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci, regs);
Expand Down Expand Up @@ -542,6 +515,7 @@ static int uhci_start(struct usb_hcd *hcd)
struct dentry *dentry;

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

Expand Down Expand Up @@ -714,8 +688,6 @@ static int uhci_start(struct usb_hcd *hcd)
configure_hc(uhci);
start_rh(uhci);

restart_timer(uhci);

udev->speed = USB_SPEED_FULL;

if (usb_hcd_register_root_hub(udev, hcd) != 0) {
Expand All @@ -730,8 +702,8 @@ static int uhci_start(struct usb_hcd *hcd)
* error exits:
*/
err_start_root_hub:
del_timer_sync(&uhci->stall_timer);
reset_hc(uhci);
del_timer_sync(&uhci->stall_timer);

err_alloc_skelqh:
for (i = 0; i < UHCI_NUM_SKELQH; i++)
Expand Down Expand Up @@ -771,13 +743,12 @@ static void uhci_stop(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);

del_timer_sync(&uhci->stall_timer);

spin_lock_irq(&uhci->lock);
reset_hc(uhci);
uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock);


del_timer_sync(&uhci->stall_timer);
release_uhci(uhci);
}

Expand Down Expand Up @@ -844,6 +815,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)

done:
spin_unlock_irq(&uhci->lock);
if (rc == 0)
del_timer_sync(&hcd->rh_timer);
return rc;
}

Expand Down Expand Up @@ -875,6 +848,9 @@ static int uhci_resume(struct usb_hcd *hcd)
suspend_rh(uhci, UHCI_RH_SUSPENDED);

spin_unlock_irq(&uhci->lock);

if (hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return 0;
}
#endif
Expand Down
12 changes: 6 additions & 6 deletions trunk/drivers/usb/host/uhci-hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,18 +327,19 @@ static inline int __interval_to_skel(int interval)
* driver learns to autosuspend.)
*/
enum uhci_rh_state {
/* In the next 4 states the HC must be halted */
UHCI_RH_RESET, /* These two must come first */
/* In the following states the HC must be halted.
* These two must come first */
UHCI_RH_RESET,
UHCI_RH_SUSPENDED,

UHCI_RH_AUTO_STOPPED,
UHCI_RH_RESUMING,

/* In the next state the HC changes from running to halted, so it
* can legally appear either way */
/* In this state the HC changes from running to halted,
* so it can legally appear either way. */
UHCI_RH_SUSPENDING,

/* In the next two states it's an error if the HC is halted.
/* In the following states it's an error if the HC is halted.
* These two must come last */
UHCI_RH_RUNNING, /* The normal state */
UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */
Expand Down Expand Up @@ -380,7 +381,6 @@ struct uhci_hcd {

unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int resume_detect:1; /* Need a Global Resume */
unsigned int hc_inaccessible:1; /* HC is suspended or dead */

/* Support for port suspend/resume/reset */
Expand Down
67 changes: 60 additions & 7 deletions trunk/drivers/usb/host/uhci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,16 @@ static int any_ports_active(struct uhci_hcd *uhci)
return 0;
}

static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int port;

if (uhci->hc_inaccessible)
return 0;

*buf = 0;
for (port = 0; port < uhci->rh_numports; ++port) {
if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) & RWC_BITS) ||
test_bit(port, &uhci->port_c_suspend))
*buf |= (1 << (port + 1));
}
if (*buf && uhci->is_stopped)
uhci->resume_detect = 1;
return !!*buf;
}

Expand Down Expand Up @@ -134,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
set_bit(port, &uhci->resuming_ports);
uhci->ports_timeout = jiffies +
msecs_to_jiffies(20);

/* Make sure we see the port again
* after the resuming period is over. */
mod_timer(&uhci_to_hcd(uhci)->rh_timer,
uhci->ports_timeout);
} else if (time_after_eq(jiffies,
uhci->ports_timeout)) {
uhci_finish_suspend(uhci, port, port_addr);
Expand All @@ -142,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
}
}

static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
int status;

spin_lock_irqsave(&uhci->lock, flags);
if (uhci->hc_inaccessible) {
status = 0;
goto done;
}

uhci_check_ports(uhci);
status = get_hub_status_data(uhci, buf);

switch (uhci->rh_state) {
case UHCI_RH_SUSPENDING:
case UHCI_RH_SUSPENDED:
/* if port change, ask to be resumed */
if (status)
usb_hcd_resume_root_hub(hcd);
break;

case UHCI_RH_AUTO_STOPPED:
/* if port change, auto start */
if (status)
wakeup_rh(uhci);
break;

case UHCI_RH_RUNNING:
/* are any devices attached? */
if (!any_ports_active(uhci)) {
uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
uhci->auto_stop_time = jiffies + HZ;
}
break;

case UHCI_RH_RUNNING_NODEVS:
/* auto-stop if nothing connected for 1 second */
if (any_ports_active(uhci))
uhci->rh_state = UHCI_RH_RUNNING;
else if (time_after_eq(jiffies, uhci->auto_stop_time))
suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
break;

default:
break;
}

done:
spin_unlock_irqrestore(&uhci->lock, flags);
return status;
}

/* size of returned buffer is part of USB spec */
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/usb/host/uhci-q.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
*/
static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
if (uhci->is_stopped)
mod_timer(&uhci->stall_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
}

Expand Down Expand Up @@ -1497,6 +1499,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
rescan:
uhci->need_rescan = 0;

uhci_clear_next_interrupt(uhci);
uhci_get_current_frame_number(uhci);

if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
Expand Down

0 comments on commit c2a53a1

Please sign in to comment.