This patch adds notifier for drivers want to be informed of the usb role switch.

Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Cc: Heikki Krogerus <heikki.kroge...@linux.intel.com>
Cc: Hans de Goede <hdego...@redhat.com>
Cc: Andy Shevchenko <andy.shevche...@gmail.com>
Cc: John Stultz <john.stu...@linaro.org>
Suggested-by: Heikki Krogerus <heikki.kroge...@linux.intel.com>
Signed-off-by: Yu Chen <cheny...@huawei.com>
---
 drivers/usb/roles/class.c | 20 +++++++++++++++++++-
 include/linux/usb/role.h  | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index f45d8df5cfb8..e2caaa665d6e 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -20,6 +20,7 @@ struct usb_role_switch {
        struct device dev;
        struct mutex lock; /* device lock*/
        enum usb_role role;
+       struct blocking_notifier_head nh;
 
        /* From descriptor */
        struct device *usb2_port;
@@ -49,8 +50,10 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, 
enum usb_role role)
        mutex_lock(&sw->lock);
 
        ret = sw->set(sw->dev.parent, role);
-       if (!ret)
+       if (!ret) {
                sw->role = role;
+               blocking_notifier_call_chain(&sw->nh, role, NULL);
+       }
 
        mutex_unlock(&sw->lock);
 
@@ -58,6 +61,20 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, 
enum usb_role role)
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_set_role);
 
+int usb_role_switch_register_notifier(struct usb_role_switch *sw,
+                                     struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&sw->nh, nb);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_register_notifier);
+
+int usb_role_switch_unregister_notifier(struct usb_role_switch *sw,
+                                       struct notifier_block *nb)
+{
+       return blocking_notifier_chain_unregister(&sw->nh, nb);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_unregister_notifier);
+
 /**
  * usb_role_switch_get_role - Get the USB role for a switch
  * @sw: USB role switch
@@ -271,6 +288,7 @@ usb_role_switch_register(struct device *parent,
                return ERR_PTR(-ENOMEM);
 
        mutex_init(&sw->lock);
+       BLOCKING_INIT_NOTIFIER_HEAD(&sw->nh);
 
        sw->allow_userspace_control = desc->allow_userspace_control;
        sw->usb2_port = desc->usb2_port;
diff --git a/include/linux/usb/role.h b/include/linux/usb/role.h
index 9684a8734757..9e1ca663387a 100644
--- a/include/linux/usb/role.h
+++ b/include/linux/usb/role.h
@@ -41,6 +41,8 @@ struct usb_role_switch_desc {
        bool allow_userspace_control;
 };
 
+
+#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
 int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role);
 enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw);
 struct usb_role_switch *usb_role_switch_get(struct device *dev);
@@ -50,5 +52,49 @@ struct usb_role_switch *
 usb_role_switch_register(struct device *parent,
                         const struct usb_role_switch_desc *desc);
 void usb_role_switch_unregister(struct usb_role_switch *sw);
+int usb_role_switch_register_notifier(struct usb_role_switch *sw,
+                                     struct notifier_block *nb);
+int usb_role_switch_unregister_notifier(struct usb_role_switch *sw,
+                                       struct notifier_block *nb);
+#else
+static inline int usb_role_switch_set_role(struct usb_role_switch *sw,
+               enum usb_role role)
+{
+       return 0;
+}
+
+static inline enum usb_role usb_role_switch_get_role(struct usb_role_switch 
*sw)
+{
+       return USB_ROLE_NONE;
+}
+
+static inline struct usb_role_switch *usb_role_switch_get(struct device *dev)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void usb_role_switch_put(struct usb_role_switch *sw) { }
+
+static inline struct usb_role_switch *
+usb_role_switch_register(struct device *parent,
+                        const struct usb_role_switch_desc *desc)
+{
+       return ERR_PTR(-ENODEV);
+}
+
+static inline void usb_role_switch_unregister(struct usb_role_switch *sw) { }
+
+static int usb_role_switch_register_notifier(struct usb_role_switch *sw,
+                                     struct notifier_block *nb)
+{
+       return -ENODEV;
+}
+
+static int usb_role_switch_unregister_notifier(struct usb_role_switch *sw,
+                                       struct notifier_block *nb)
+{
+       return -ENODEV;
+}
+#endif
 
 #endif /* __LINUX_USB_ROLE_H */
-- 
2.15.0-rc2

Reply via email to