Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: Add new PM callback methods for USB

This patch (as1129) adds support for the new PM callbacks to usbcore.
The new callbacks merely invoke the same old USB power management
routines as the old ones did.

A minor improvement is that the callbacks are present only in the
"USB-device" device_type structure, rather than in the bus_type
structure. This way they will be invoked only for USB devices, not
for USB interfaces. The core USB PM routines automatically handle
suspending and resuming interfaces along with their devices.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
f2189c47 55151d7d

+72 -19
+2 -13
drivers/usb/core/driver.c
··· 1630 1630 return status; 1631 1631 } 1632 1632 1633 - static int usb_suspend(struct device *dev, pm_message_t message) 1633 + int usb_suspend(struct device *dev, pm_message_t message) 1634 1634 { 1635 1635 struct usb_device *udev; 1636 1636 1637 - if (!is_usb_device(dev)) /* Ignore PM for interfaces */ 1638 - return 0; 1639 1637 udev = to_usb_device(dev); 1640 1638 1641 1639 /* If udev is already suspended, we can skip this suspend and ··· 1652 1654 return usb_external_suspend_device(udev, message); 1653 1655 } 1654 1656 1655 - static int usb_resume(struct device *dev) 1657 + int usb_resume(struct device *dev) 1656 1658 { 1657 1659 struct usb_device *udev; 1658 1660 1659 - if (!is_usb_device(dev)) /* Ignore PM for interfaces */ 1660 - return 0; 1661 1661 udev = to_usb_device(dev); 1662 1662 1663 1663 /* If udev->skip_sys_resume is set then udev was already suspended ··· 1667 1671 return usb_external_resume_device(udev); 1668 1672 } 1669 1673 1670 - #else 1671 - 1672 - #define usb_suspend NULL 1673 - #define usb_resume NULL 1674 - 1675 1674 #endif /* CONFIG_PM */ 1676 1675 1677 1676 struct bus_type usb_bus_type = { 1678 1677 .name = "usb", 1679 1678 .match = usb_device_match, 1680 1679 .uevent = usb_uevent, 1681 - .suspend = usb_suspend, 1682 - .resume = usb_resume, 1683 1680 };
+67 -6
drivers/usb/core/usb.c
··· 219 219 } 220 220 #endif /* CONFIG_HOTPLUG */ 221 221 222 - struct device_type usb_device_type = { 223 - .name = "usb_device", 224 - .release = usb_release_dev, 225 - .uevent = usb_dev_uevent, 226 - }; 227 - 228 222 #ifdef CONFIG_PM 229 223 230 224 static int ksuspend_usb_init(void) ··· 238 244 destroy_workqueue(ksuspend_usb_wq); 239 245 } 240 246 247 + /* USB device Power-Management thunks. 248 + * There's no need to distinguish here between quiescing a USB device 249 + * and powering it down; the generic_suspend() routine takes care of 250 + * it by skipping the usb_port_suspend() call for a quiesce. And for 251 + * USB interfaces there's no difference at all. 252 + */ 253 + 254 + static int usb_dev_prepare(struct device *dev) 255 + { 256 + return 0; /* Implement eventually? */ 257 + } 258 + 259 + static void usb_dev_complete(struct device *dev) 260 + { 261 + /* Currently used only for rebinding interfaces */ 262 + usb_resume(dev); /* Implement eventually? */ 263 + } 264 + 265 + static int usb_dev_suspend(struct device *dev) 266 + { 267 + return usb_suspend(dev, PMSG_SUSPEND); 268 + } 269 + 270 + static int usb_dev_resume(struct device *dev) 271 + { 272 + return usb_resume(dev); 273 + } 274 + 275 + static int usb_dev_freeze(struct device *dev) 276 + { 277 + return usb_suspend(dev, PMSG_FREEZE); 278 + } 279 + 280 + static int usb_dev_thaw(struct device *dev) 281 + { 282 + return usb_resume(dev); 283 + } 284 + 285 + static int usb_dev_poweroff(struct device *dev) 286 + { 287 + return usb_suspend(dev, PMSG_HIBERNATE); 288 + } 289 + 290 + static int usb_dev_restore(struct device *dev) 291 + { 292 + return usb_resume(dev); 293 + } 294 + 295 + static struct pm_ops usb_device_pm_ops = { 296 + .prepare = usb_dev_prepare, 297 + .complete = usb_dev_complete, 298 + .suspend = usb_dev_suspend, 299 + .resume = usb_dev_resume, 300 + .freeze = usb_dev_freeze, 301 + .thaw = usb_dev_thaw, 302 + .poweroff = usb_dev_poweroff, 303 + .restore = usb_dev_restore, 304 + }; 305 + 241 306 #else 242 307 243 308 #define ksuspend_usb_init() 0 244 309 #define ksuspend_usb_cleanup() do {} while (0) 310 + #define usb_device_pm_ops (*(struct pm_ops *)0) 245 311 246 312 #endif /* CONFIG_PM */ 313 + 314 + struct device_type usb_device_type = { 315 + .name = "usb_device", 316 + .release = usb_release_dev, 317 + .uevent = usb_dev_uevent, 318 + .pm = &usb_device_pm_ops, 319 + }; 247 320 248 321 249 322 /* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+3
drivers/usb/core/usb.h
··· 41 41 42 42 #ifdef CONFIG_PM 43 43 44 + extern int usb_suspend(struct device *dev, pm_message_t msg); 45 + extern int usb_resume(struct device *dev); 46 + 44 47 extern void usb_autosuspend_work(struct work_struct *work); 45 48 extern int usb_port_suspend(struct usb_device *dev); 46 49 extern int usb_port_resume(struct usb_device *dev);