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.willi...@intel.com>
---
 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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to