From 6e30d7cba992d626c9d16b3873a7b90c700d0e95 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Fri, 11 Jan 2013 20:10:38 +0800 Subject: usb: Add driver/usb/core/(port.c,hub.h) files This patch is to create driver/usb/core/(port.c,hub.h) files and move usb port related code into port.c. Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 drivers/usb/core/port.c (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c new file mode 100644 index 000000000000..2bc1cef4e478 --- /dev/null +++ b/drivers/usb/core/port.c @@ -0,0 +1,66 @@ +/* + * usb port device code + * + * Copyright (C) 2012 Intel Corp + * + * Author: Lan Tianyu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + */ + +#include "hub.h" + +static void usb_port_device_release(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + + kfree(port_dev); +} + +struct device_type usb_port_device_type = { + .name = "usb_port", + .release = usb_port_device_release, +}; + +int usb_hub_create_port_device(struct usb_hub *hub, int port1) +{ + struct usb_port *port_dev = NULL; + int retval; + + port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); + if (!port_dev) { + retval = -ENOMEM; + goto exit; + } + + hub->ports[port1 - 1] = port_dev; + port_dev->dev.parent = hub->intfdev; + port_dev->dev.type = &usb_port_device_type; + dev_set_name(&port_dev->dev, "port%d", port1); + + retval = device_register(&port_dev->dev); + if (retval) + goto error_register; + + return 0; + +error_register: + put_device(&port_dev->dev); +exit: + return retval; +} + +void usb_hub_remove_port_device(struct usb_hub *hub, + int port1) +{ + device_unregister(&hub->ports[port1 - 1]->dev); +} + -- cgit v1.2.3 From 9f7344fbaf191de63df315c7e0fa4c976e2ea419 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Sat, 19 Jan 2013 22:30:19 +0800 Subject: usb: fix compilation error and warning of driver/usb/core/port.c on arm and blackfin This patch is to fix compilation error and warning on the arm and blackfin. Add linux/slab.h head file to driver/usb/core/port.c. These are reported from 0-DAY kernel build testing backend. head: 6e30d7cba992d626c9d16b3873a7b90c700d0e95 commit: 6e30d7cba992d626c9d16b3873a7b90c700d0e95 [26/26] usb: Add driver/usb/core/(port.c,hub.h) files config: make ARCH=arm at91_dt_defconfig All error/warnings: drivers/usb/core/port.c: In function 'usb_port_device_release': >> drivers/usb/core/port.c:25:2: error: implicit declaration of function 'kfree' [-Werror=implicit-function-declaration] drivers/usb/core/port.c: In function 'usb_hub_create_port_device': >> drivers/usb/core/port.c:38:2: error: implicit declaration of function 'kzalloc' [-Werror=implicit-function-declaration] >> drivers/usb/core/port.c:38:40: error: 'GFP_KERNEL' undeclared (first use in this function) drivers/usb/core/port.c:38:40: note: each undeclared identifier is reported only once for each function it appears in cc1: some warnings being treated as errors head: 6e30d7cba992d626c9d16b3873a7b90c700d0e95 commit: 6e30d7cba992d626c9d16b3873a7b90c700d0e95 [26/26] usb: Add driver/usb/core/(port.c,hub.h) files config: make ARCH=blackfin BF526-EZBRD_defconfig All warnings: drivers/usb/core/port.c: In function 'usb_port_device_release': drivers/usb/core/port.c:25:2: error: implicit declaration of function 'kfree' [-Werror=implicit-function-declaration] drivers/usb/core/port.c: In function 'usb_hub_create_port_device': drivers/usb/core/port.c:38:2: error: implicit declaration of function 'kzalloc' [-Werror=implicit-function-declaration] >> drivers/usb/core/port.c:38:11: warning: assignment makes pointer from integer without a cast [enabled by default] cc1: some warnings being treated as errors Reported-by: Fengguang Wu Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 2bc1cef4e478..3734850120ae 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -16,6 +16,8 @@ * */ +#include + #include "hub.h" static void usb_port_device_release(struct device *dev) -- cgit v1.2.3 From cef7468caff29d3333fba4d0ececd82063ce80d5 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Sun, 20 Jan 2013 01:53:32 +0800 Subject: usb: Add "portX/connect_type" attribute to expose usb port's connect type Some platforms provide usb port connect types through ACPI. This patch is to add this new attribute to expose these information to user space. Acked-by: Alan Stern Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 9 +++++++ drivers/usb/core/port.c | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) (limited to 'drivers/usb/core/port.c') diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index b6fbe514a869..c8baaf53594a 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -227,3 +227,12 @@ Contact: Lan Tianyu Description: The /sys/bus/usb/devices/.../(hub interface)/portX is usb port device's sysfs directory. + +What: /sys/bus/usb/devices/.../(hub interface)/portX/connect_type +Date: January 2013 +Contact: Lan Tianyu +Description: + Some platforms provide usb port connect types through ACPI. + This attribute is to expose these information to user space. + The file will read "hotplug", "wired" and "not used" if the + information is available, and "unknown" otherwise. diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 3734850120ae..fe5959fc021b 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -20,6 +20,48 @@ #include "hub.h" +static const struct attribute_group *port_dev_group[]; + +static ssize_t show_port_connect_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_port *port_dev = to_usb_port(dev); + char *result; + + switch (port_dev->connect_type) { + case USB_PORT_CONNECT_TYPE_HOT_PLUG: + result = "hotplug"; + break; + case USB_PORT_CONNECT_TYPE_HARD_WIRED: + result = "hardwired"; + break; + case USB_PORT_NOT_USED: + result = "not used"; + break; + default: + result = "unknown"; + break; + } + + return sprintf(buf, "%s\n", result); +} +static DEVICE_ATTR(connect_type, S_IRUGO, show_port_connect_type, + NULL); + +static struct attribute *port_dev_attrs[] = { + &dev_attr_connect_type.attr, + NULL, +}; + +static struct attribute_group port_dev_attr_grp = { + .attrs = port_dev_attrs, +}; + +static const struct attribute_group *port_dev_group[] = { + &port_dev_attr_grp, + NULL, +}; + static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); @@ -45,6 +87,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) hub->ports[port1 - 1] = port_dev; port_dev->dev.parent = hub->intfdev; + port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; dev_set_name(&port_dev->dev, "port%d", port1); -- cgit v1.2.3 From 88bb965ed711e8a5984e70208ebc901a6ff4141f Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 23 Jan 2013 04:26:27 +0800 Subject: usb: Register usb port's acpi power resources This patch is to register usb port's acpi power resources. Create link between usb port device and its acpi power resource. Acked-by: Alan Stern Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 5 +++++ drivers/usb/core/usb-acpi.c | 18 ++++++++++++++++++ drivers/usb/core/usb.h | 6 ++++++ 3 files changed, 29 insertions(+) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index fe5959fc021b..153e799e7320 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -66,6 +66,7 @@ static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); + usb_acpi_unregister_power_resources(dev); kfree(port_dev); } @@ -95,6 +96,10 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) if (retval) goto error_register; + retval = usb_acpi_register_power_resources(&port_dev->dev); + if (retval && retval != -ENODEV) + dev_warn(&port_dev->dev, "the port can't register its ACPI power resource.\n"); + return 0; error_register: diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index cef4252bb31a..8d304b0b5abf 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -216,6 +216,24 @@ static struct acpi_bus_type usb_acpi_bus = { .find_device = usb_acpi_find_device, }; +int usb_acpi_register_power_resources(struct device *dev) +{ + acpi_handle port_handle = DEVICE_ACPI_HANDLE(dev); + + if (!port_handle) + return -ENODEV; + + return acpi_power_resource_register_device(dev, port_handle); +} + +void usb_acpi_unregister_power_resources(struct device *dev) +{ + acpi_handle port_handle = DEVICE_ACPI_HANDLE(dev); + + if (port_handle) + acpi_power_resource_unregister_device(dev, port_handle); +} + int usb_acpi_register(void) { return register_acpi_bus_type(&usb_acpi_bus); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index a7f20bde0e5e..601b044f90f0 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -191,7 +191,13 @@ extern int usb_acpi_register(void); extern void usb_acpi_unregister(void); extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, int port1); +extern int usb_acpi_register_power_resources(struct device *dev); +extern void usb_acpi_unregister_power_resources(struct device *dev); #else static inline int usb_acpi_register(void) { return 0; }; static inline void usb_acpi_unregister(void) { }; +static inline int usb_acpi_register_power_resources(struct device *dev) + { return 0; }; +static inline void usb_acpi_unregister_power_resources(struct device *dev) + { }; #endif -- cgit v1.2.3 From 971fcd492cebf544714f12d94549d2f0d2002645 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 23 Jan 2013 04:26:29 +0800 Subject: usb: add runtime pm support for usb port device This patch is to add runtime pm callback for usb port device. Set/clear PORT_POWER feature in the resume/suspend callback. Add portnum for struct usb_port to record port number. Do pm_rumtime_get_sync/put(portdev) when a device is plugged/unplugged to prevent it from being powered off when it is active. Acked-by: Alan Stern Acked-by: Rafael J. Wysocki Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 27 +++++++++++++++++++++++++++ drivers/usb/core/hub.h | 4 ++++ drivers/usb/core/port.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 29ca6ed3bea8..7fb163365d02 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -714,6 +714,27 @@ static void hub_tt_work(struct work_struct *work) spin_unlock_irqrestore (&hub->tt.lock, flags); } +/** + * usb_hub_set_port_power - control hub port's power state + * @hdev: target hub + * @port1: port index + * @set: expected status + * + * call this function to control port's power via setting or + * clearing the port's PORT_POWER feature. + */ +int usb_hub_set_port_power(struct usb_device *hdev, int port1, + bool set) +{ + int ret; + + if (set) + ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); + else + ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); + return ret; +} + /** * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub * @urb: an URB associated with the failed or incomplete split transaction @@ -1569,6 +1590,7 @@ static void hub_disconnect(struct usb_interface *intf) kfree(hub->status); kfree(hub->buffer); + pm_suspend_ignore_children(&intf->dev, false); kref_put(&hub->kref, hub_release); } @@ -1671,6 +1693,7 @@ descriptor_error: usb_set_intfdata (intf, hub); intf->needs_remote_wakeup = 1; + pm_suspend_ignore_children(&intf->dev, true); if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs++; @@ -1997,6 +2020,8 @@ void usb_disconnect(struct usb_device **pdev) sysfs_remove_link(&udev->dev.kobj, "port"); sysfs_remove_link(&port_dev->dev.kobj, "device"); + + pm_runtime_put(&port_dev->dev); } usb_remove_ep_devs(&udev->ep0); @@ -2307,6 +2332,8 @@ int usb_new_device(struct usb_device *udev) sysfs_remove_link(&udev->dev.kobj, "port"); goto fail; } + + pm_runtime_get_sync(&port_dev->dev); } (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index c472058f8f27..452e5cd7b249 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -79,12 +79,14 @@ struct usb_hub { * @dev: generic device interface * @port_owner: port's owner * @connect_type: port's connect type + * @portnum: port index num based one */ struct usb_port { struct usb_device *child; struct device dev; struct dev_state *port_owner; enum usb_port_connect_type connect_type; + u8 portnum; }; #define to_usb_port(_dev) \ @@ -94,4 +96,6 @@ extern int usb_hub_create_port_device(struct usb_hub *hub, int port1); extern void usb_hub_remove_port_device(struct usb_hub *hub, int port1); +extern int usb_hub_set_port_power(struct usb_device *hdev, + int port1, bool set); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 153e799e7320..d288dfed6ccf 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -17,6 +17,7 @@ */ #include +#include #include "hub.h" @@ -70,9 +71,50 @@ static void usb_port_device_release(struct device *dev) kfree(port_dev); } +#ifdef CONFIG_USB_SUSPEND +static int usb_port_runtime_resume(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_interface *intf = to_usb_interface(dev->parent); + int retval; + + usb_autopm_get_interface(intf); + retval = usb_hub_set_port_power(hdev, port_dev->portnum, true); + usb_autopm_put_interface(intf); + return retval; +} + +static int usb_port_runtime_suspend(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_interface *intf = to_usb_interface(dev->parent); + int retval; + + if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) + == PM_QOS_FLAGS_ALL) + return -EAGAIN; + + usb_autopm_get_interface(intf); + retval = usb_hub_set_port_power(hdev, port_dev->portnum, false); + usb_autopm_put_interface(intf); + return retval; +} +#endif + +static const struct dev_pm_ops usb_port_pm_ops = { +#ifdef CONFIG_USB_SUSPEND + .runtime_suspend = usb_port_runtime_suspend, + .runtime_resume = usb_port_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; + struct device_type usb_port_device_type = { .name = "usb_port", .release = usb_port_device_release, + .pm = &usb_port_pm_ops, }; int usb_hub_create_port_device(struct usb_hub *hub, int port1) @@ -87,6 +129,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) } hub->ports[port1 - 1] = port_dev; + port_dev->portnum = port1; port_dev->dev.parent = hub->intfdev; port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; @@ -96,6 +139,9 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) if (retval) goto error_register; + pm_runtime_set_active(&port_dev->dev); + pm_runtime_enable(&port_dev->dev); + retval = usb_acpi_register_power_resources(&port_dev->dev); if (retval && retval != -ENODEV) dev_warn(&port_dev->dev, "the port can't register its ACPI power resource.\n"); -- cgit v1.2.3 From ad493e5e580546e6c3024b76a41535476da1546a Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 23 Jan 2013 04:26:30 +0800 Subject: usb: add usb port auto power off mechanism This patch is to add usb port auto power off mechanism. When usb device is suspending, usb core will suspend usb port and usb port runtime pm callback will clear PORT_POWER feature to power off port if all conditions were met. These conditions are remote wakeup disable, pm qos NO_POWER_OFF flag clear and persist enable. When it resumes, power on port again. Add did_runtime_put in the struct usb_port to ensure pm_runtime_get/put(portdev) to be called pairedly. Set did_runtime_put to true when call pm_runtime_put(portdev) during suspending. The pm_runtime_get(portdev) only will be called when did_runtime_put is set to true during resuming. Set did_runtime_put to false after calling pm_runtime_get(portdev). Make clear_port_feature() and hdev_to_hub() as global symbol. Rename clear_port_feature() to usb_clear_port_feature() and hdev_to_hub() to usb_hub_to_struct_hub(). Extend hub_port_debounce() with the fuction of debouncing to be connected. Add two wraps: hub_port_debounce_be_connected() and hub_port_debouce_be_stable(). Increase HUB_DEBOUNCE_TIMEOUT to 2000 because some usb ssds needs around 1.5 or more to make the hub port status to be connected steadily after being powered off and powered on. Acked-by: Alan Stern Acked-by: Rafael J. Wysocki Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 161 +++++++++++++++++++++++++++++++----------------- drivers/usb/core/hub.h | 21 +++++++ drivers/usb/core/port.c | 40 +++++++++++- 3 files changed, 164 insertions(+), 58 deletions(-) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 7fb163365d02..0883364e7347 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -108,7 +109,7 @@ MODULE_PARM_DESC(use_both_schemes, DECLARE_RWSEM(ehci_cf_port_reset_rwsem); EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); -#define HUB_DEBOUNCE_TIMEOUT 1500 +#define HUB_DEBOUNCE_TIMEOUT 2000 #define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STABLE 100 @@ -127,7 +128,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus) } /* Note that hdev or one of its children must be locked! */ -static struct usb_hub *hdev_to_hub(struct usb_device *hdev) +struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) { if (!hdev || !hdev->actconfig || !hdev->maxchild) return NULL; @@ -301,7 +302,7 @@ static void usb_set_lpm_parameters(struct usb_device *udev) if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER) return; - hub = hdev_to_hub(udev->parent); + hub = usb_hub_to_struct_hub(udev->parent); /* It doesn't take time to transition the roothub into U0, since it * doesn't have an upstream link. */ @@ -393,7 +394,7 @@ static int clear_hub_feature(struct usb_device *hdev, int feature) /* * USB 2.0 spec Section 11.24.2.2 */ -static int clear_port_feature(struct usb_device *hdev, int port1, int feature) +int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature) { return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, @@ -586,7 +587,7 @@ static void kick_khubd(struct usb_hub *hub) void usb_kick_khubd(struct usb_device *hdev) { - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); if (hub) kick_khubd(hub); @@ -608,7 +609,7 @@ void usb_wakeup_notification(struct usb_device *hdev, if (!hdev) return; - hub = hdev_to_hub(hdev); + hub = usb_hub_to_struct_hub(hdev); if (hub) { set_bit(portnum, hub->wakeup_bits); kick_khubd(hub); @@ -727,11 +728,16 @@ int usb_hub_set_port_power(struct usb_device *hdev, int port1, bool set) { int ret; + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_port *port_dev = hub->ports[port1 - 1]; if (set) ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); else - ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); + ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); + + if (!ret) + port_dev->power_is_on = set; return ret; } @@ -811,7 +817,11 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) dev_dbg(hub->intfdev, "trying to enable port power on " "non-switchable hub\n"); for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) - set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); + if (hub->ports[port1 - 1]->power_is_on) + set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); + else + usb_clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_POWER); /* Wait at least 100 msec for power to become stable */ delay = max(pgood_delay, (unsigned) 100); @@ -905,7 +915,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) if (hub_is_superspeed(hub->hdev)) ret = hub_usb3_port_disable(hub, port1); else - ret = clear_port_feature(hdev, port1, + ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); } if (ret) @@ -954,7 +964,7 @@ int usb_remove_device(struct usb_device *udev) if (!udev->parent) /* Can't remove a root hub */ return -EINVAL; - hub = hdev_to_hub(udev->parent); + hub = usb_hub_to_struct_hub(udev->parent); intf = to_usb_interface(hub->intfdev); usb_autopm_get_interface(intf); @@ -1086,7 +1096,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) * Do not disable USB3 protocol ports. */ if (!hub_is_superspeed(hdev)) { - clear_port_feature(hdev, port1, + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); portstatus &= ~USB_PORT_STAT_ENABLE; } else { @@ -1098,18 +1108,18 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) /* Clear status-change flags; we'll debounce later */ if (portchange & USB_PORT_STAT_C_CONNECTION) { need_debounce_delay = true; - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); } if (portchange & USB_PORT_STAT_C_ENABLE) { need_debounce_delay = true; - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); } if ((portchange & USB_PORT_STAT_C_BH_RESET) && hub_is_superspeed(hub->hdev)) { need_debounce_delay = true; - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_BH_PORT_RESET); } /* We can forget about a "removed" device when there's a @@ -1143,10 +1153,16 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) set_bit(port1, hub->change_bits); } else if (udev->persist_enabled) { + struct usb_port *port_dev = hub->ports[port1 - 1]; + #ifdef CONFIG_PM udev->reset_resume = 1; #endif - set_bit(port1, hub->change_bits); + /* Don't set the change_bits when the device + * was powered off. + */ + if (port_dev->power_is_on) + set_bit(port1, hub->change_bits); } else { /* The power session is gone; tell khubd */ @@ -1712,7 +1728,7 @@ static int hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) { struct usb_device *hdev = interface_to_usbdev (intf); - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); /* assert ifno == 0 (part of hub spec) */ switch (code) { @@ -1758,7 +1774,7 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1, /* This assumes that devices not managed by the hub driver * will always have maxchild equal to 0. */ - *ppowner = &(hdev_to_hub(hdev)->ports[port1 - 1]->port_owner); + *ppowner = &(usb_hub_to_struct_hub(hdev)->ports[port1 - 1]->port_owner); return 0; } @@ -1795,7 +1811,7 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) { - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); int n; for (n = 0; n < hdev->maxchild; n++) { @@ -1812,13 +1828,13 @@ bool usb_device_is_owned(struct usb_device *udev) if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) return false; - hub = hdev_to_hub(udev->parent); + hub = usb_hub_to_struct_hub(udev->parent); return !!hub->ports[udev->portnum - 1]->port_owner; } static void recursively_mark_NOTATTACHED(struct usb_device *udev) { - struct usb_hub *hub = hdev_to_hub(udev); + struct usb_hub *hub = usb_hub_to_struct_hub(udev); int i; for (i = 0; i < udev->maxchild; ++i) { @@ -1987,7 +2003,7 @@ static void hub_free_dev(struct usb_device *udev) void usb_disconnect(struct usb_device **pdev) { struct usb_device *udev = *pdev; - struct usb_hub *hub = hdev_to_hub(udev); + struct usb_hub *hub = usb_hub_to_struct_hub(udev); int i; /* mark the device as inactive, so any further urb submissions for @@ -2015,13 +2031,16 @@ void usb_disconnect(struct usb_device **pdev) usb_hcd_synchronize_unlinks(udev); if (udev->parent) { - struct usb_port *port_dev = - hdev_to_hub(udev->parent)->ports[udev->portnum - 1]; + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + struct usb_port *port_dev = hub->ports[udev->portnum - 1]; sysfs_remove_link(&udev->dev.kobj, "port"); sysfs_remove_link(&port_dev->dev.kobj, "device"); - pm_runtime_put(&port_dev->dev); + if (!port_dev->did_runtime_put) + pm_runtime_put(&port_dev->dev); + else + port_dev->did_runtime_put = false; } usb_remove_ep_devs(&udev->ep0); @@ -2210,7 +2229,7 @@ static void set_usb_port_removable(struct usb_device *udev) if (!hdev) return; - hub = hdev_to_hub(udev->parent); + hub = usb_hub_to_struct_hub(udev->parent); wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); @@ -2318,8 +2337,8 @@ int usb_new_device(struct usb_device *udev) /* Create link files between child device and usb port device. */ if (udev->parent) { - struct usb_port *port_dev = - hdev_to_hub(udev->parent)->ports[udev->portnum - 1]; + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + struct usb_port *port_dev = hub->ports[udev->portnum - 1]; err = sysfs_create_link(&udev->dev.kobj, &port_dev->dev.kobj, "port"); @@ -2567,14 +2586,14 @@ static void hub_port_finish_reset(struct usb_hub *hub, int port1, /* FALL THROUGH */ case -ENOTCONN: case -ENODEV: - clear_port_feature(hub->hdev, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_RESET); if (hub_is_superspeed(hub->hdev)) { - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_BH_PORT_RESET); - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_PORT_LINK_STATE); - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); } if (udev) @@ -2748,10 +2767,10 @@ static int check_port_resume_type(struct usb_device *udev, /* Late port handoff can set status-change bits */ if (portchange & USB_PORT_STAT_C_CONNECTION) - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); if (portchange & USB_PORT_STAT_C_ENABLE) - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); } @@ -2852,7 +2871,9 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); */ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) { - struct usb_hub *hub = hdev_to_hub(udev->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + struct usb_port *port_dev = hub->ports[udev->portnum - 1]; + enum pm_qos_flags_status pm_qos_stat; int port1 = udev->portnum; int status; @@ -2945,6 +2966,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) udev->port_is_suspended = 1; msleep(10); } + + /* + * Check whether current status meets the requirement of + * usb port power off mechanism + */ + pm_qos_stat = dev_pm_qos_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF); + if (!udev->do_remote_wakeup + && pm_qos_stat != PM_QOS_FLAGS_ALL + && udev->persist_enabled + && !status) { + pm_runtime_put_sync(&port_dev->dev); + port_dev->did_runtime_put = true; + } + usb_mark_last_busy(hub->hdev); return status; } @@ -3070,11 +3106,22 @@ static int finish_port_resume(struct usb_device *udev) */ int usb_port_resume(struct usb_device *udev, pm_message_t msg) { - struct usb_hub *hub = hdev_to_hub(udev->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); + struct usb_port *port_dev = hub->ports[udev->portnum - 1]; int port1 = udev->portnum; int status; u16 portchange, portstatus; + if (port_dev->did_runtime_put) { + status = pm_runtime_get_sync(&port_dev->dev); + port_dev->did_runtime_put = false; + if (status < 0) { + dev_dbg(&udev->dev, "can't resume usb port, status %d\n", + status); + return status; + } + } + /* Skip the initial Clear-Suspend step for a remote wakeup */ status = hub_port_status(hub, port1, &portstatus, &portchange); if (status == 0 && !port_is_suspended(hub, portstatus)) @@ -3088,7 +3135,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) if (hub_is_superspeed(hub->hdev)) status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0); else - status = clear_port_feature(hub->hdev, + status = usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); if (status) { dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", @@ -3114,11 +3161,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) udev->port_is_suspended = 0; if (hub_is_superspeed(hub->hdev)) { if (portchange & USB_PORT_STAT_C_LINK_STATE) - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_PORT_LINK_STATE); } else { if (portchange & USB_PORT_STAT_C_SUSPEND) - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_SUSPEND); } } @@ -3174,7 +3221,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) int usb_port_resume(struct usb_device *udev, pm_message_t msg) { - struct usb_hub *hub = hdev_to_hub(udev->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); int port1 = udev->portnum; int status; u16 portchange, portstatus; @@ -3753,7 +3800,7 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm); * every 25ms for transient disconnects. When the port status has been * unchanged for 100ms it returns the port status. */ -static int hub_port_debounce(struct usb_hub *hub, int port1) +int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected) { int ret; int total_time, stable_time = 0; @@ -3767,7 +3814,9 @@ static int hub_port_debounce(struct usb_hub *hub, int port1) if (!(portchange & USB_PORT_STAT_C_CONNECTION) && (portstatus & USB_PORT_STAT_CONNECTION) == connection) { - stable_time += HUB_DEBOUNCE_STEP; + if (!must_be_connected || + (connection == USB_PORT_STAT_CONNECTION)) + stable_time += HUB_DEBOUNCE_STEP; if (stable_time >= HUB_DEBOUNCE_STABLE) break; } else { @@ -3776,7 +3825,7 @@ static int hub_port_debounce(struct usb_hub *hub, int port1) } if (portchange & USB_PORT_STAT_C_CONNECTION) { - clear_port_feature(hub->hdev, port1, + usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_CONNECTION); } @@ -4288,7 +4337,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (portchange & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE)) { - status = hub_port_debounce(hub, port1); + status = hub_port_debounce_be_stable(hub, port1); if (status < 0) { if (printk_ratelimit()) dev_err(hub_dev, "connect-debounce failed, " @@ -4467,7 +4516,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, if (!hub_is_superspeed(hdev)) { if (!(portchange & USB_PORT_STAT_C_SUSPEND)) return 0; - clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); + usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); } else { if (!udev || udev->state != USB_STATE_SUSPENDED || (portstatus & USB_PORT_STAT_LINK_STATE) != @@ -4595,7 +4644,7 @@ static void hub_events(void) continue; if (portchange & USB_PORT_STAT_C_CONNECTION) { - clear_port_feature(hdev, i, + usb_clear_port_feature(hdev, i, USB_PORT_FEAT_C_CONNECTION); connect_change = 1; } @@ -4606,7 +4655,7 @@ static void hub_events(void) "port %d enable change, " "status %08x\n", i, portstatus); - clear_port_feature(hdev, i, + usb_clear_port_feature(hdev, i, USB_PORT_FEAT_C_ENABLE); /* @@ -4637,7 +4686,7 @@ static void hub_events(void) dev_dbg(hub_dev, "over-current change on port " "%d\n", i); - clear_port_feature(hdev, i, + usb_clear_port_feature(hdev, i, USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ hub_power_on(hub, true); @@ -4651,7 +4700,7 @@ static void hub_events(void) dev_dbg (hub_dev, "reset change on port %d\n", i); - clear_port_feature(hdev, i, + usb_clear_port_feature(hdev, i, USB_PORT_FEAT_C_RESET); } if ((portchange & USB_PORT_STAT_C_BH_RESET) && @@ -4659,18 +4708,18 @@ static void hub_events(void) dev_dbg(hub_dev, "warm reset change on port %d\n", i); - clear_port_feature(hdev, i, + usb_clear_port_feature(hdev, i, USB_PORT_FEAT_C_BH_PORT_RESET); } if (portchange & USB_PORT_STAT_C_LINK_STATE) { - clear_port_feature(hub->hdev, i, + usb_clear_port_feature(hub->hdev, i, USB_PORT_FEAT_C_PORT_LINK_STATE); } if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { dev_warn(hub_dev, "config error on port %d\n", i); - clear_port_feature(hub->hdev, i, + usb_clear_port_feature(hub->hdev, i, USB_PORT_FEAT_C_PORT_CONFIG_ERROR); } @@ -4954,7 +5003,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) dev_dbg(&udev->dev, "%s for root hub!\n", __func__); return -EISDIR; } - parent_hub = hdev_to_hub(parent_hdev); + parent_hub = usb_hub_to_struct_hub(parent_hdev); /* Disable LPM and LTM while we reset the device and reinstall the alt * settings. Device-initiated LPM settings, and system exit latency @@ -5210,7 +5259,7 @@ EXPORT_SYMBOL_GPL(usb_queue_reset_device); struct usb_device *usb_hub_find_child(struct usb_device *hdev, int port1) { - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); if (port1 < 1 || port1 > hdev->maxchild) return NULL; @@ -5227,7 +5276,7 @@ EXPORT_SYMBOL_GPL(usb_hub_find_child); void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, enum usb_port_connect_type type) { - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); hub->ports[port1 - 1]->connect_type = type; } @@ -5243,7 +5292,7 @@ void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, enum usb_port_connect_type usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) { - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); return hub->ports[port1 - 1]->connect_type; } @@ -5301,7 +5350,7 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev, acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, int port1) { - struct usb_hub *hub = hdev_to_hub(hdev); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev); } diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 452e5cd7b249..80ab9ee07017 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -80,6 +80,8 @@ struct usb_hub { * @port_owner: port's owner * @connect_type: port's connect type * @portnum: port index num based one + * @power_is_on: port's power state + * @did_runtime_put: port has done pm_runtime_put(). */ struct usb_port { struct usb_device *child; @@ -87,6 +89,8 @@ struct usb_port { struct dev_state *port_owner; enum usb_port_connect_type connect_type; u8 portnum; + unsigned power_is_on:1; + unsigned did_runtime_put:1; }; #define to_usb_port(_dev) \ @@ -98,4 +102,21 @@ extern void usb_hub_remove_port_device(struct usb_hub *hub, int port1); extern int usb_hub_set_port_power(struct usb_device *hdev, int port1, bool set); +extern struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev); +extern int hub_port_debounce(struct usb_hub *hub, int port1, + bool must_be_connected); +extern int usb_clear_port_feature(struct usb_device *hdev, + int port1, int feature); + +static inline int hub_port_debounce_be_connected(struct usb_hub *hub, + int port1) +{ + return hub_port_debounce(hub, port1, true); +} + +static inline int hub_port_debounce_be_stable(struct usb_hub *hub, + int port1) +{ + return hub_port_debounce(hub, port1, false); +} diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index d288dfed6ccf..280433d80887 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -77,10 +77,36 @@ static int usb_port_runtime_resume(struct device *dev) struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + int port1 = port_dev->portnum; int retval; + if (!hub) + return -EINVAL; + usb_autopm_get_interface(intf); - retval = usb_hub_set_port_power(hdev, port_dev->portnum, true); + set_bit(port1, hub->busy_bits); + + retval = usb_hub_set_port_power(hdev, port1, true); + if (port_dev->child && !retval) { + /* + * Wait for usb hub port to be reconnected in order to make + * the resume procedure successful. + */ + retval = hub_port_debounce_be_connected(hub, port1); + if (retval < 0) { + dev_dbg(&port_dev->dev, "can't get reconnection after setting port power on, status %d\n", + retval); + goto out; + } + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + + /* Set return value to 0 if debounce successful */ + retval = 0; + } + +out: + clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); return retval; } @@ -90,14 +116,23 @@ static int usb_port_runtime_suspend(struct device *dev) struct usb_port *port_dev = to_usb_port(dev); struct usb_device *hdev = to_usb_device(dev->parent->parent); struct usb_interface *intf = to_usb_interface(dev->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + int port1 = port_dev->portnum; int retval; + if (!hub) + return -EINVAL; + if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == PM_QOS_FLAGS_ALL) return -EAGAIN; usb_autopm_get_interface(intf); - retval = usb_hub_set_port_power(hdev, port_dev->portnum, false); + set_bit(port1, hub->busy_bits); + retval = usb_hub_set_port_power(hdev, port1, false); + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + clear_bit(port1, hub->busy_bits); usb_autopm_put_interface(intf); return retval; } @@ -130,6 +165,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) hub->ports[port1 - 1] = port_dev; port_dev->portnum = port1; + port_dev->power_is_on = true; port_dev->dev.parent = hub->intfdev; port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; -- cgit v1.2.3 From f6cced1a08b475c5ac946823bb057714be7af4f6 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 23 Jan 2013 04:26:31 +0800 Subject: usb: expose usb port's pm qos flags to user space This patch is to expose usb port's pm qos flags(pm_qos_no_power_off, pm_qos_remote_wakeup) to user space. User can set pm_qos_no_power_off flag to prohibit the port from being powered off. Acked-by: Alan Stern Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 280433d80887..9a15b26944ec 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -67,6 +67,7 @@ static void usb_port_device_release(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); + dev_pm_qos_hide_flags(dev); usb_acpi_unregister_power_resources(dev); kfree(port_dev); } @@ -176,7 +177,15 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) goto error_register; pm_runtime_set_active(&port_dev->dev); - pm_runtime_enable(&port_dev->dev); + + /* It would be dangerous if user space couldn't + * prevent usb device from being powered off. So don't + * enable port runtime pm if failed to expose port's pm qos. + */ + if (!dev_pm_qos_expose_flags(&port_dev->dev, + PM_QOS_FLAG_NO_POWER_OFF)) + pm_runtime_enable(&port_dev->dev); + retval = usb_acpi_register_power_resources(&port_dev->dev); if (retval && retval != -ENODEV) -- cgit v1.2.3 From 192fef18d0f5ac9a05a93ff6314fc9865c10fbf9 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Wed, 23 Jan 2013 04:26:32 +0800 Subject: usb: enable usb port device's async suspend. This patch is to set power.async_suspend for usb port in order to allow it to be suspended and resumed asynchronously during system sleep transitions. The power.async_suspend flag is also set for devices that don't have suspend or resume callbacks, because otherwise they would make the main suspend/resume thread wait for their "asynchronous" children (during suspend) or parents (during resume), effectively negating the possible gains from executing these devices' suspend and resume callbacks asynchronously. Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 9a15b26944ec..5df143dbd759 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -186,6 +186,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) PM_QOS_FLAG_NO_POWER_OFF)) pm_runtime_enable(&port_dev->dev); + device_enable_async_suspend(&port_dev->dev); retval = usb_acpi_register_power_resources(&port_dev->dev); if (retval && retval != -ENODEV) -- cgit v1.2.3 From 3b2ab2b84c68fb92accbc735927bc8221e4de973 Mon Sep 17 00:00:00 2001 From: Lan Tianyu Date: Tue, 29 Jan 2013 00:59:06 +0800 Subject: Revert "usb: Register usb port's acpi power resources" This reverts commit 88bb965ed711e8a5984e70208ebc901a6ff4141f. The linux-next branch of linux-pm tree has replaced acpi_power_resource_(un)register_device() with new routines. Commit 88bb965 will cause conflict in the linux-next tree. So revert it and this will not affect other functions. Will send a new patch with new routines after 3.9 merge window. Signed-off-by: Lan Tianyu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/port.c | 6 ------ drivers/usb/core/usb-acpi.c | 18 ------------------ drivers/usb/core/usb.h | 6 ------ 3 files changed, 30 deletions(-) (limited to 'drivers/usb/core/port.c') diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 5df143dbd759..797f9d514732 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -68,7 +68,6 @@ static void usb_port_device_release(struct device *dev) struct usb_port *port_dev = to_usb_port(dev); dev_pm_qos_hide_flags(dev); - usb_acpi_unregister_power_resources(dev); kfree(port_dev); } @@ -187,11 +186,6 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) pm_runtime_enable(&port_dev->dev); device_enable_async_suspend(&port_dev->dev); - - retval = usb_acpi_register_power_resources(&port_dev->dev); - if (retval && retval != -ENODEV) - dev_warn(&port_dev->dev, "the port can't register its ACPI power resource.\n"); - return 0; error_register: diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 8d304b0b5abf..cef4252bb31a 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -216,24 +216,6 @@ static struct acpi_bus_type usb_acpi_bus = { .find_device = usb_acpi_find_device, }; -int usb_acpi_register_power_resources(struct device *dev) -{ - acpi_handle port_handle = DEVICE_ACPI_HANDLE(dev); - - if (!port_handle) - return -ENODEV; - - return acpi_power_resource_register_device(dev, port_handle); -} - -void usb_acpi_unregister_power_resources(struct device *dev) -{ - acpi_handle port_handle = DEVICE_ACPI_HANDLE(dev); - - if (port_handle) - acpi_power_resource_unregister_device(dev, port_handle); -} - int usb_acpi_register(void) { return register_acpi_bus_type(&usb_acpi_bus); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 601b044f90f0..a7f20bde0e5e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -191,13 +191,7 @@ extern int usb_acpi_register(void); extern void usb_acpi_unregister(void); extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, int port1); -extern int usb_acpi_register_power_resources(struct device *dev); -extern void usb_acpi_unregister_power_resources(struct device *dev); #else static inline int usb_acpi_register(void) { return 0; }; static inline void usb_acpi_unregister(void) { }; -static inline int usb_acpi_register_power_resources(struct device *dev) - { return 0; }; -static inline void usb_acpi_unregister_power_resources(struct device *dev) - { }; #endif -- cgit v1.2.3