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