From b69147b5893d130ca5de6dfe1be4bb15690b8c94 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 10 Oct 2007 16:30:12 -0400 Subject: [PATCH] --- yaml --- r: 67927 b: refs/heads/master c: 271f9e68f3450ac8d1ff3bda36581f1ec0d0cc1f h: refs/heads/master i: 67925: aa812cd6f1ffedd018d6de5685b2a4a03e6aa1e8 67923: 9e6b21493541c1e108c410d30dea7d67dd5805a3 67919: db1eb913aac8f6487f14ab6b2c91cc8d80608d0a v: v3 --- [refs] | 2 +- trunk/drivers/usb/core/driver.c | 27 ++++++++++++++++++++------- trunk/include/linux/usb.h | 1 + 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/[refs] b/[refs] index 42a48d75c02e..e6aa26af0fb1 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 32fe01985aa2cb2562f6fc171e526e279abe10db +refs/heads/master: 271f9e68f3450ac8d1ff3bda36581f1ec0d0cc1f diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c index 3f734240e0ec..8c1eac27f2de 100644 --- a/trunk/drivers/usb/core/driver.c +++ b/trunk/drivers/usb/core/driver.c @@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev) static int usb_suspend(struct device *dev, pm_message_t message) { + struct usb_device *udev; + if (!is_usb_device(dev)) /* Ignore PM for interfaces */ return 0; - return usb_external_suspend_device(to_usb_device(dev), message); + udev = to_usb_device(dev); + + /* If udev is already suspended, we can skip this suspend and + * we should also skip the upcoming system resume. */ + if (udev->state == USB_STATE_SUSPENDED) { + udev->skip_sys_resume = 1; + return 0; + } + + udev->skip_sys_resume = 0; + return usb_external_suspend_device(udev, message); } static int usb_resume(struct device *dev) @@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev) return 0; udev = to_usb_device(dev); - /* If autoresume is disabled then we also want to prevent resume - * during system wakeup. However, a "persistent-device" reset-resume - * after power loss counts as a wakeup event. So allow a - * reset-resume to occur if remote wakeup is enabled. */ - if (udev->autoresume_disabled) { + /* If udev->skip_sys_resume is set then udev was already suspended + * when the system suspend started, so we don't want to resume + * udev during this system wakeup. However a reset-resume counts + * as a wakeup event, so allow a reset-resume to occur if remote + * wakeup is enabled. */ + if (udev->skip_sys_resume) { if (!(udev->reset_resume && udev->do_remote_wakeup)) - return -EPERM; + return -EHOSTUNREACH; } return usb_external_resume_device(udev); } diff --git a/trunk/include/linux/usb.h b/trunk/include/linux/usb.h index c10935fdc03a..c5c8f169d3cf 100644 --- a/trunk/include/linux/usb.h +++ b/trunk/include/linux/usb.h @@ -430,6 +430,7 @@ struct usb_device { unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */ unsigned autosuspend_disabled:1; /* autosuspend and autoresume */ unsigned autoresume_disabled:1; /* disabled by the user */ + unsigned skip_sys_resume:1; /* skip the next system resume */ #endif }; #define to_usb_device(d) container_of(d, struct usb_device, dev)