[RFC PATCH 03/15] usbcore: add sysfs linkage for connector peers

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

 



Use the "connector" association information provided by platform
firmware to create links between peer ports in a connector.

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

diff --git a/drivers/usb/core/usb-platform.c b/drivers/usb/core/usb-platform.c
index 476ac3fa47c2..6b39d1fde8e4 100644
--- a/drivers/usb/core/usb-platform.c
+++ b/drivers/usb/core/usb-platform.c
@@ -11,6 +11,10 @@
 #include <linux/device.h>
 #include "usb-platform.h"
 
+#define for_each_connector_peer(peer, port, c) \
+	list_for_each_entry(peer, &(c)->ports, node) \
+		if (port != peer)
+
 static void domain_release(struct kref *kref)
 {
 	struct usb_domain *udom = container_of(kref, struct usb_domain, kref);
@@ -85,15 +89,58 @@ static void check_connector(struct usb_connector *uconn,
 static void add_port_connector(struct usb_port *port_dev,
 			       struct usb_connector *uconn)
 {
+	struct device *dev = &port_dev->dev;
+	struct usb_port *peer;
+	char name[40], name2[40];
+
 	list_add(&port_dev->node, &uconn->ports);
 	port_dev->connector = uconn;
 	check_connector(uconn, port_dev);
+
+	for_each_connector_peer(peer, port_dev, uconn) {
+		struct device *tgt = &peer->dev;
+		int rc;
+
+		rc = snprintf(name, sizeof(name), "peer:%s-%s",
+			      dev_name(dev->parent), dev_name(dev));
+		if (rc >= sizeof(name)
+		    || sysfs_create_link(&tgt->kobj, &dev->kobj, name) != 0)
+			continue;
+
+		rc = snprintf(name2, sizeof(name), "peer:%s-%s",
+			      dev_name(tgt->parent), dev_name(tgt));
+		if (rc >= sizeof(name2)
+		    || sysfs_create_link(&dev->kobj, &tgt->kobj, name2) != 0)
+			sysfs_remove_link(&tgt->kobj, name);
+	}
 }
 
-static void remove_port_connector(struct usb_port *port_dev)
+static void remove_port_connector(struct usb_port *port_dev,
+				  struct usb_connector *uconn)
 {
+	struct device *dev = &port_dev->dev;
+	struct usb_port *peer;
+	char name[40];
+
 	list_del_init(&port_dev->node);
 	port_dev->connector = NULL;
+
+	for_each_connector_peer(peer, port_dev, uconn) {
+		struct device *tgt = &peer->dev;
+		int rc;
+
+		rc = snprintf(name, sizeof(name), "peer:%s-%s",
+			      dev_name(dev->parent), dev_name(dev));
+		if (rc >= sizeof(name))
+			continue;
+		sysfs_remove_link(&tgt->kobj, name);
+
+		rc = snprintf(name, sizeof(name), "peer:%s-%s",
+			      dev_name(tgt->parent), dev_name(tgt));
+		if (rc >= sizeof(name))
+			continue;
+		sysfs_remove_link(&dev->kobj, name);
+	}
 }
 
 int usb_domain_pair_port(struct usb_domain *udom, struct usb_port *port_dev,
@@ -144,7 +191,7 @@ void usb_domain_remove_port(struct usb_domain *udom, struct usb_port *port_dev)
 
 		list_for_each_entry(p, &uconn->ports, node)
 			if (p == port_dev) {
-				remove_port_connector(port_dev);
+				remove_port_connector(port_dev, uconn);
 				break;
 			}
 

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