This patch is to add "auto" option to attribute portX/control. When echo "auto", the port's feature PORT_POWER would be clear if the port's connect type was mark not-used(connectability and visibility are both cleared) and with no device attached. Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx> --- This patchset is based on the following patchset http://marc.info/?l=linux-usb&m=134517695007182&w=2 usb: make usb port a real device usb: move children to struct usb_port usb/acpi: Bind ACPI node to USB port, not usb_device. usb/acpi: Store info on device removability. xhci: Handle clear PORT_POWER feature. usb/acpi: Use ACPI methods to power off ports. usb: Fail a get config when the port is powered off. usb : Add sysfs files to control port power. v2: add "auto" option process in the hub_power_on() --- drivers/usb/core/hub.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 3def91e..07c62dd 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -42,6 +42,7 @@ enum port_power_policy { USB_PORT_POWER_ON = 0, USB_PORT_POWER_OFF, + USB_PORT_POWER_AUTO, }; struct usb_port { @@ -101,6 +102,7 @@ struct usb_hub { static const char on_string[] = "on"; static const char off_string[] = "off"; +static const char auto_string[] = "auto"; static const struct attribute_group *port_dev_group[]; static inline int hub_is_superspeed(struct usb_device *hdev) @@ -842,6 +844,7 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) unsigned delay; u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); + struct usb_port *pport; /* Enable power on each port. Some hubs have reserved values * of LPSM (> 2) in their descriptors, even though they are @@ -854,13 +857,18 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) else dev_dbg(hub->intfdev, "trying to enable port power on " "non-switchable hub\n"); - for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) - if (hub->ports[port1 - 1]->port_power_policy - == USB_PORT_POWER_ON) - set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); - else + for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) { + pport = hub->ports[port1 - 1]; + + if (pport->port_power_policy == USB_PORT_POWER_OFF || + (pport->port_power_policy == USB_PORT_POWER_AUTO + && pport->connect_type == USB_PORT_NOT_USED + && !pport->child)) clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_POWER); + USB_PORT_FEAT_POWER); + else + set_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); @@ -4703,6 +4711,9 @@ static ssize_t show_port_power_control(struct device *dev, case USB_PORT_POWER_OFF: result = off_string; break; + case USB_PORT_POWER_AUTO: + result = auto_string; + break; default: return -EINVAL; } @@ -4741,6 +4752,18 @@ static ssize_t store_port_power_control(struct device *dev, usb_autopm_put_interface(intf); if (ret < 0) return -EIO; + } else if (len == sizeof(auto_string) - 1 + && strncmp(buf, auto_string, len) == 0) { + hub_port->port_power_policy = USB_PORT_POWER_AUTO; + if (hub_port->connect_type + == USB_PORT_NOT_USED && !hub_port->child) { + usb_autopm_get_interface(intf); + ret = clear_port_feature(hdev, port1, + USB_PORT_FEAT_POWER); + usb_autopm_put_interface(intf); + if (ret < 0) + return -EIO; + } } else return -EINVAL; -- 1.7.9.5 -- 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