Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 10767
b: refs/heads/master
c: 979d519
h: refs/heads/master
i:
  10765: 94a6833
  10763: b919a80
  10759: 6bd8983
  10751: f249ade
v: v3
  • Loading branch information
David Brownell authored and Greg Kroah-Hartman committed Oct 28, 2005
1 parent 44bcdcb commit d53ed56
Show file tree
Hide file tree
Showing 7 changed files with 112 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: 9293677af3dace2645dec0d0808efa02d36bf47b
refs/heads/master: 979d5199fee9e80290ddeb532e5993bd15506712
1 change: 1 addition & 0 deletions trunk/drivers/base/power/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev)
runtime_resume(dev);
up(&dpm_sem);
}
EXPORT_SYMBOL(dpm_runtime_resume);


/**
Expand Down
64 changes: 57 additions & 7 deletions trunk/drivers/usb/core/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1143,10 +1143,20 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
else switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
doit:
usb_get_dev (urb->dev);
list_add_tail (&urb->urb_list, &ep->urb_list);
status = 0;
break;
case HC_STATE_SUSPENDED:
/* HC upstream links (register access, wakeup signaling) can work
* even when the downstream links (and DMA etc) are quiesced; let
* usbcore talk to the root hub.
*/
if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
&& urb->dev->parent == NULL)
goto doit;
/* FALL THROUGH */
default:
status = -ESHUTDOWN;
break;
Expand Down Expand Up @@ -1294,12 +1304,6 @@ static int hcd_unlink_urb (struct urb *urb, int status)
goto done;
}

/* running ~= hc unlink handshake works (irq, timer, etc)
* halted ~= no unlink handshake is needed
* suspended, resuming == should never happen
*/
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);

/* insist the urb is still queued */
list_for_each(tmp, &ep->urb_list) {
if (tmp == &urb->urb_list)
Expand Down Expand Up @@ -1459,6 +1463,8 @@ static int hcd_hub_resume (struct usb_bus *bus)
hcd = container_of (bus, struct usb_hcd, self);
if (!hcd->driver->hub_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
return 0;
hcd->state = HC_STATE_RESUMING;
status = hcd->driver->hub_resume (hcd);
if (status == 0)
Expand All @@ -1471,14 +1477,58 @@ static int hcd_hub_resume (struct usb_bus *bus)
return status;
}

/*
* usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
* @hcd: host controller for this root hub
*
* This call arranges that usb_hcd_resume_root_hub() is safe to call later;
* that the HCD's root hub polling is deactivated; and that the root's hub
* driver is suspended. HCDs may call this to autosuspend when their root
* hub's downstream ports are all inactive: unpowered, disconnected,
* disabled, or suspended.
*
* The HCD will autoresume on device connect change detection (using SRP
* or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
* from any ports that are suspended (if that is enabled). In most cases,
* overcurrent signaling (on powered ports) will also start autoresume.
*
* Always called with IRQs blocked.
*/
void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
{
struct urb *urb;

spin_lock (&hcd_root_hub_lock);
usb_suspend_root_hub (hcd->self.root_hub);

/* force status urb to complete/unlink while suspended */
if (hcd->status_urb) {
urb = hcd->status_urb;
urb->status = -ECONNRESET;
urb->hcpriv = NULL;
urb->actual_length = 0;

del_timer (&hcd->rh_timer);
hcd->poll_pending = 0;
hcd->status_urb = NULL;
} else
urb = NULL;
spin_unlock (&hcd_root_hub_lock);
hcd->state = HC_STATE_SUSPENDED;

if (urb)
usb_hcd_giveback_urb (hcd, urb, NULL);
}
EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);

/**
* usb_hcd_resume_root_hub - called by HCD to resume its root hub
* @hcd: host controller for this root hub
*
* The USB host controller calls this function when its root hub is
* suspended (with the remote wakeup feature enabled) and a remote
* wakeup request is received. It queues a request for khubd to
* resume the root hub.
* resume the root hub (that is, manage its downstream ports again).
*/
void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
{
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/usb/core/hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ extern long usb_calc_bus_time (int speed, int is_input,

extern struct usb_bus *usb_alloc_bus (struct usb_operations *);

extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);

extern void usb_set_device_state(struct usb_device *udev,
Expand Down
45 changes: 37 additions & 8 deletions trunk/drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,18 @@ static void hub_power_on(struct usb_hub *hub)
msleep(max(pgood_delay, (unsigned) 100));
}

static void hub_quiesce(struct usb_hub *hub)
static inline void __hub_quiesce(struct usb_hub *hub)
{
/* stop khubd and related activity */
/* (nonblocking) khubd and related activity won't re-trigger */
hub->quiescing = 1;
hub->activating = 0;
hub->resume_root_hub = 0;
}

static void hub_quiesce(struct usb_hub *hub)
{
/* (blocking) stop khubd and related activity */
__hub_quiesce(hub);
usb_kill_urb(hub->urb);
if (hub->has_indicators)
cancel_delayed_work(&hub->leds);
Expand All @@ -467,6 +474,7 @@ static void hub_activate(struct usb_hub *hub)

hub->quiescing = 0;
hub->activating = 1;
hub->resume_root_hub = 0;
status = usb_submit_urb(hub->urb, GFP_NOIO);
if (status < 0)
dev_err(hub->intfdev, "activate --> %d\n", status);
Expand Down Expand Up @@ -1959,6 +1967,18 @@ static int hub_resume(struct usb_interface *intf)
return 0;
}

void usb_suspend_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);

/* This also makes any led blinker stop retriggering. We're called
* from irq, so the blinker might still be scheduled. Caller promises
* that the root hub status URB will be canceled.
*/
__hub_quiesce(hub);
mark_quiesced(to_usb_interface(hub->intfdev));
}

void usb_resume_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
Expand Down Expand Up @@ -2616,21 +2636,30 @@ static void hub_events(void)
intf = to_usb_interface(hub->intfdev);
hub_dev = &intf->dev;

dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
i = hub->resume_root_hub;

dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n",
hdev->state, hub->descriptor
? hub->descriptor->bNbrPorts
: 0,
/* NOTE: expects max 15 ports... */
(u16) hub->change_bits[0],
(u16) hub->event_bits[0]);
(u16) hub->event_bits[0],
i ? ", resume root" : "");

usb_get_intf(intf);
i = hub->resume_root_hub;
spin_unlock_irq(&hub_event_lock);

/* Is this is a root hub wanting to be resumed? */
if (i)
usb_resume_device(hdev);
/* Is this is a root hub wanting to reactivate the downstream
* ports? If so, be sure the interface resumes even if its
* stub "device" node was never suspended.
*/
if (i) {
extern void dpm_runtime_resume(struct device *);

dpm_runtime_resume(&hdev->dev);
dpm_runtime_resume(&intf->dev);
}

/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
Expand Down
20 changes: 14 additions & 6 deletions trunk/drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,7 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)

/* USB devices enter SUSPEND state through their hubs, but can be
* marked for FREEZE as soon as their children are already idled.
* But those semantics are useless, so we equate the two (sigh).
*/
if (dev->driver == &usb_generic_driver) {
if (dev->power.power_state.event == message.event)
Expand All @@ -1435,10 +1436,6 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
status = device_for_each_child(dev, NULL, verify_suspended);
if (status)
return status;
if (message.event == PM_EVENT_FREEZE) {
dev->power.power_state = message;
return 0;
}
return usb_suspend_device (to_usb_device(dev));
}

Expand Down Expand Up @@ -1471,14 +1468,22 @@ static int usb_generic_resume(struct device *dev)
{
struct usb_interface *intf;
struct usb_driver *driver;
struct usb_device *udev;
int status;

if (dev->power.power_state.event == PM_EVENT_ON)
return 0;

/* mark things as "on" immediately, no matter what errors crop up */
dev->power.power_state.event = PM_EVENT_ON;

/* devices resume through their hubs */
if (dev->driver == &usb_generic_driver)
if (dev->driver == &usb_generic_driver) {
udev = to_usb_device(dev);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;
return usb_resume_device (to_usb_device(dev));
}

if ((dev->driver == NULL) ||
(dev->driver_data == &usb_generic_driver_data))
Expand All @@ -1487,11 +1492,14 @@ static int usb_generic_resume(struct device *dev)
intf = to_usb_interface(dev);
driver = to_usb_driver(dev->driver);

udev = interface_to_usbdev(intf);
if (udev->state == USB_STATE_NOTATTACHED)
return 0;

/* if driver was suspended, it has a resume method;
* however, sysfs can wrongly mark things as suspended
* (on the "no suspend method" FIXME path above)
*/
mark_active(intf);
if (driver->resume) {
status = driver->resume(intf);
if (status) {
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/usb/core/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extern void usb_lock_all_devices(void);
extern void usb_unlock_all_devices(void);

extern void usb_kick_khubd(struct usb_device *dev);
extern void usb_suspend_root_hub(struct usb_device *hdev);
extern void usb_resume_root_hub(struct usb_device *dev);

extern int usb_hub_init(void);
Expand Down

0 comments on commit d53ed56

Please sign in to comment.