The connectors may be registered after the ports, so the
"connector" links need to be created for the ports also when
ever a new connector gets registered.

Signed-off-by: Heikki Krogerus <heikki.kroge...@linux.intel.com>
---
 drivers/usb/typec/class.c       |  9 +++--
 drivers/usb/typec/class.h       |  4 +--
 drivers/usb/typec/port-mapper.c | 62 +++++++++++++++++++++++++++++++--
 3 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c
index ff199e2d26c7b..f1c2d823c6509 100644
--- a/drivers/usb/typec/class.c
+++ b/drivers/usb/typec/class.c
@@ -1601,7 +1601,6 @@ static void typec_release(struct device *dev)
        ida_destroy(&port->mode_ids);
        typec_switch_put(port->sw);
        typec_mux_put(port->mux);
-       free_pld(port->pld);
        kfree(port->cap);
        kfree(port);
 }
@@ -2027,7 +2026,9 @@ struct typec_port *typec_register_port(struct device 
*parent,
                return ERR_PTR(ret);
        }
 
-       port->pld = get_pld(&port->dev);
+       ret = typec_link_ports(port);
+       if (ret)
+               dev_warn(&port->dev, "failed to create symlinks (%d)\n", ret);
 
        return port;
 }
@@ -2041,8 +2042,10 @@ EXPORT_SYMBOL_GPL(typec_register_port);
  */
 void typec_unregister_port(struct typec_port *port)
 {
-       if (!IS_ERR_OR_NULL(port))
+       if (!IS_ERR_OR_NULL(port)) {
+               typec_unlink_ports(port);
                device_unregister(&port->dev);
+       }
 }
 EXPORT_SYMBOL_GPL(typec_unregister_port);
 
diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h
index 52294f7020a8b..aef03eb7e1523 100644
--- a/drivers/usb/typec/class.h
+++ b/drivers/usb/typec/class.h
@@ -79,7 +79,7 @@ extern const struct device_type typec_port_dev_type;
 extern struct class typec_mux_class;
 extern struct class typec_class;
 
-void *get_pld(struct device *dev);
-void free_pld(void *pld);
+int typec_link_ports(struct typec_port *connector);
+void typec_unlink_ports(struct typec_port *connector);
 
 #endif /* __USB_TYPEC_CLASS__ */
diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c
index 5bee7a97242fe..fae736eb0601e 100644
--- a/drivers/usb/typec/port-mapper.c
+++ b/drivers/usb/typec/port-mapper.c
@@ -34,7 +34,7 @@ static int acpi_pld_match(const struct acpi_pld_info *pld1,
        return 0;
 }
 
-void *get_pld(struct device *dev)
+static void *get_pld(struct device *dev)
 {
 #ifdef CONFIG_ACPI
        struct acpi_pld_info *pld;
@@ -53,7 +53,7 @@ void *get_pld(struct device *dev)
 #endif
 }
 
-void free_pld(void *pld)
+static void free_pld(void *pld)
 {
 #ifdef CONFIG_ACPI
        ACPI_FREE(pld);
@@ -217,3 +217,61 @@ void typec_unlink_port(struct device *port)
        class_for_each_device(&typec_class, NULL, port, port_match_and_unlink);
 }
 EXPORT_SYMBOL_GPL(typec_unlink_port);
+
+static int each_port(struct device *port, void *connector)
+{
+       struct port_node *node;
+       int ret;
+
+       node = create_port_node(port);
+       if (IS_ERR(node))
+               return PTR_ERR(node);
+
+       if (!connector_match(connector, node)) {
+               remove_port_node(node);
+               return 0;
+       }
+
+       ret = link_port(to_typec_port(connector), node);
+       if (ret) {
+               remove_port_node(node->pld);
+               return ret;
+       }
+
+       get_device(connector);
+
+       return 0;
+}
+
+int typec_link_ports(struct typec_port *con)
+{
+       int ret = 0;
+
+       con->pld = get_pld(&con->dev);
+       if (!con->pld)
+               return 0;
+
+       ret = usb_for_each_port(&con->dev, each_port);
+       if (ret)
+               typec_unlink_ports(con);
+
+       return ret;
+}
+
+void typec_unlink_ports(struct typec_port *con)
+{
+       struct port_node *node;
+       struct port_node *tmp;
+
+       mutex_lock(&con->port_list_lock);
+
+       list_for_each_entry_safe(node, tmp, &con->port_list, list) {
+               __unlink_port(con, node);
+               remove_port_node(node);
+               put_device(&con->dev);
+       }
+
+       mutex_unlock(&con->port_list_lock);
+
+       free_pld(con->pld);
+}
-- 
2.30.2

Reply via email to