Now that userspace can discover the constraints keeping a port powered, require
it to explicitly disable hotplug capability before powering off a port.  This
makes the 'connect_type' attribute writable, and must be set to 'hardwired'
before a port is a candidate for poweroff.

Signed-off-by: Dan Williams <[email protected]>
---
 Documentation/ABI/testing/sysfs-bus-usb |    2 ++
 drivers/usb/core/port.c                 |   36 ++++++++++++++++++++++++++++++-
 2 files changed, 37 insertions(+), 1 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-usb 
b/Documentation/ABI/testing/sysfs-bus-usb
index 91bfcfcfbfe3..65db3a686de9 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -160,6 +160,8 @@ Description:
                          port
                'pm_qos_no_power_off': child inactive, pm qos flag keeps
                                       power enabled
+               'hotplug': child inactive, remaining powered to detect
+                          hotplug events
                'wakeup enabled': child inactive, port kept powered to
                                  handle remote wakeup events
                'persist disabled': child inactive, but child device
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index f7d1cd8a97d3..977e5b137b79 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -46,7 +46,38 @@ static ssize_t connect_type_show(struct device *dev,
 
        return sprintf(buf, "%s\n", result);
 }
-static DEVICE_ATTR_RO(connect_type);
+
+static ssize_t connect_type_store(struct device *dev, struct device_attribute 
*attr,
+                                 const char *buf, size_t len)
+{
+       struct usb_port *port_dev = to_usb_port(dev);
+       ssize_t sz = len;
+       int i;
+       struct action { const char *str; enum usb_port_connect_type type; };
+       static const struct action action[] = {
+               { .str = "hotplug", .type = USB_PORT_CONNECT_TYPE_HOT_PLUG, },
+               { .str = "hardwired", .type = USB_PORT_CONNECT_TYPE_HARD_WIRED 
},
+       };
+
+       if (buf[len-1] == '\n' || buf[len-1] == '\0')
+               sz--;
+
+       for (i = 0; i < ARRAY_SIZE(action); i++) {
+               const struct action *act = &action[i];
+
+               if (sz == strlen(act->str)
+                   && strncmp(buf, act->str, sz) == 0) {
+                       pm_runtime_get_sync(&port_dev->dev);
+                       port_dev->connect_type = act->type;
+                       pm_runtime_put_sync(&port_dev->dev);
+                       return len;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static DEVICE_ATTR_RW(connect_type);
 
 static struct attribute *port_dev_attrs[] = {
        &dev_attr_connect_type.attr,
@@ -103,6 +134,9 @@ static const char *power_on_reason(struct usb_port 
*port_dev)
        if (dev_pm_qos_flags(&port_dev->dev, flag) == PM_QOS_FLAGS_ALL)
                return "pm_qos_no_power_off";
 
+       if (port_dev->connect_type < USB_PORT_CONNECT_TYPE_HARD_WIRED)
+               return "hotplug";
+
        udev = usb_port_get_child(port_dev);
        if (udev && udev->do_remote_wakeup)
                reason = "wakeup enabled";

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to