[PATCH v2 2/3] usb: roles: Add API to register notifiers
From: Paul Cercueil
Date: Wed Dec 11 2019 - 10:51:31 EST
Add usb_role_switch_notifier_register() and
usb_role_switch_notifier_unregister().
The registered notifiers will be called when the USB role is changed.
Signed-off-by: Paul Cercueil <paul@xxxxxxxxxxxxxxx>
---
Notes:
v2: New patch
drivers/usb/roles/class.c | 24 +++++++++++++++++++++++-
include/linux/usb/role.h | 20 ++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c
index 8273126ffdf4..9b122b504b98 100644
--- a/drivers/usb/roles/class.c
+++ b/drivers/usb/roles/class.c
@@ -10,6 +10,7 @@
#include <linux/usb/role.h>
#include <linux/property.h>
#include <linux/device.h>
+#include <linux/notifier.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -19,6 +20,7 @@ static struct class *role_class;
struct usb_role_switch {
struct device dev;
struct mutex lock; /* device lock*/
+ struct blocking_notifier_head notifier_chain;
enum usb_role role;
/* From descriptor */
@@ -49,8 +51,11 @@ 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;
+ ret = blocking_notifier_call_chain(&sw->notifier_chain,
+ (long)role, sw);
+ }
mutex_unlock(&sw->lock);
@@ -85,6 +90,22 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
}
EXPORT_SYMBOL_GPL(usb_role_switch_get_role);
+int
+usb_role_switch_register_notifier(struct usb_role_switch *sw,
+ struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&sw->notifier_chain, 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->notifier_chain, nb);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_unregister_notifier);
+
static void *usb_role_switch_match(struct device_connection *con, int ep,
void *data)
{
@@ -317,6 +338,7 @@ usb_role_switch_register(struct device *parent,
return ERR_PTR(-ENOMEM);
mutex_init(&sw->lock);
+ BLOCKING_INIT_NOTIFIER_HEAD(&sw->notifier_chain);
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 efac3af83d6b..5f67d42cd28d 100644
--- a/include/linux/usb/role.h
+++ b/include/linux/usb/role.h
@@ -6,6 +6,7 @@
#include <linux/device.h>
struct usb_role_switch;
+struct notifier_block;
enum usb_role {
USB_ROLE_NONE,
@@ -50,6 +51,11 @@ struct usb_role_switch *usb_role_switch_get(struct device *dev);
struct usb_role_switch *fwnode_usb_role_switch_get(struct fwnode_handle *node);
void usb_role_switch_put(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);
+
struct usb_role_switch *
usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode);
@@ -82,6 +88,20 @@ fwnode_usb_role_switch_get(struct fwnode_handle *node)
static inline void usb_role_switch_put(struct usb_role_switch *sw) { }
+static inline int
+usb_role_switch_register_notifier(struct usb_role_switch *sw,
+ struct notifier_block *nb)
+{
+ return ERR_PTR(-ENODEV);
+}
+
+static inline int
+usb_role_switch_unregister_notifier(struct usb_role_switch *sw,
+ struct notifier_block *nb)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline struct usb_role_switch *
usb_role_switch_register(struct device *parent,
const struct usb_role_switch_desc *desc)
--
2.24.0