[RFC PATCH 12/15] usbcore: allow the connect_type of ports to be changed

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



hotplug ports maintain power awaiting hotplug events.  Allow userspace to
override this disctinction on a per port basis.

Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>
---
 drivers/usb/core/port.c         |   32 +++++++++++++++++++++++++++++-
 drivers/usb/core/usb-platform.c |   42 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/core/usb-platform.h |    2 ++
 3 files changed, 75 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index d609b25746d2..71fbedaf8a93 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -47,7 +47,37 @@ 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) {
+			usb_connector_set_connect_type(port_dev, act->type);
+			return len;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static DEVICE_ATTR_RW(connect_type);
 
 static struct attribute *port_dev_attrs[] = {
 	&dev_attr_connect_type.attr,
diff --git a/drivers/usb/core/usb-platform.c b/drivers/usb/core/usb-platform.c
index 0e24110e8ba2..ce559994760e 100644
--- a/drivers/usb/core/usb-platform.c
+++ b/drivers/usb/core/usb-platform.c
@@ -91,6 +91,48 @@ bool usb_connector_notify_flags(struct usb_port *port_dev, s32 mask, bool set)
 	return true;
 }
 
+void usb_connector_set_connect_type(struct usb_port *port_dev,
+				    enum usb_port_connect_type type)
+{
+	LIST_HEAD(tmp);
+	struct usb_port *p;
+	struct usb_domain *udom;
+	int flag = PM_QOS_FLAG_NO_NOTIFY;
+	struct usb_connector *uconn = port_dev->connector;
+
+	/* if for some reason userspace does not want hotplug settings
+	 * synced
+	 */
+	if (dev_pm_qos_flags(&port_dev->dev, flag) == PM_QOS_FLAGS_ALL
+	    || !uconn) {
+		pm_runtime_get_sync(&port_dev->dev);
+		port_dev->connect_type = type;
+		pm_runtime_put(&port_dev->dev);
+	}
+
+	udom = uconn->domain;
+	mutex_lock(&udom->lock);
+	uconn->connect_type = type;
+	list_for_each_entry(port_dev, &uconn->ports, node) {
+		pm_runtime_get_sync(&port_dev->dev);
+		port_dev->connect_type = type;
+	}
+
+	/* order the resulting suspensions disconnected ports first */
+	list_for_each_entry_safe(port_dev, p, &uconn->ports, node) {
+		if (port_dev->child)
+			list_move(&port_dev->node, &tmp);
+		else
+			pm_runtime_put(&port_dev->dev);
+	}
+
+	list_for_each_entry_safe(port_dev, p, &tmp, node) {
+		list_move(&port_dev->node, &uconn->ports);
+		pm_runtime_put(&port_dev->dev);
+	}
+	mutex_unlock(&udom->lock);
+}
+
 static struct usb_connector *create_connector(struct usb_domain *udom,
 					      struct usb_port *port_dev,
 					      size_t pair_data)
diff --git a/drivers/usb/core/usb-platform.h b/drivers/usb/core/usb-platform.h
index 648dbe6d9e54..f73bc309eef3 100644
--- a/drivers/usb/core/usb-platform.h
+++ b/drivers/usb/core/usb-platform.h
@@ -52,3 +52,5 @@ bool usb_connector_notify_flags(struct usb_port *port_dev, s32 mask, bool set);
 enum usb_connector_state usb_connector_state(struct usb_port *port_dev);
 void usb_connector_connect(struct usb_port *port_dev);
 void usb_connector_disconnect(struct usb_port *port_dev);
+void usb_connector_set_connect_type(struct usb_port *port_dev,
+				    enum usb_port_connect_type type);

--
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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux