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 <dan.j.williams@xxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html