Signed-off-by: Elson Roy Serrao <quic_eserrao@xxxxxxxxxxx>
---
drivers/usb/gadget/composite.c | 32 ++++++++++++++++++++++++++++++++
drivers/usb/gadget/udc/core.c | 9 +++++++++
include/linux/usb/composite.h | 1 +
include/linux/usb/gadget.h | 2 ++
4 files changed, 44 insertions(+)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 403563c..6bdce23 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -490,6 +490,38 @@ int usb_interface_id(struct usb_configuration *config,
}
EXPORT_SYMBOL_GPL(usb_interface_id);
+int usb_func_wakeup(struct usb_function *func)
+{
+ int ret, id;
+ unsigned long flags;
+
+ if (!func || !func->config || !func->config->cdev ||
+ !func->config->cdev->gadget)
+ return -EINVAL;
+
+ DBG(func->config->cdev, "%s function wakeup\n", func->name);
+
+ spin_lock_irqsave(&func->config->cdev->lock, flags);
+
+ for (id = 0; id < MAX_CONFIG_INTERFACES; id++)
+ if (func->config->interface[id] == func)
+ break;
+
+ if (id == MAX_CONFIG_INTERFACES) {
+ ERROR(func->config->cdev, "Invalid function id:%d\n", id);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = usb_gadget_func_wakeup(func->config->cdev->gadget, id);
+
+err:
+ spin_unlock_irqrestore(&func->config->cdev->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(usb_func_wakeup);
+
static u8 encode_bMaxPower(enum usb_device_speed speed,
struct usb_configuration *c)
{
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 7886497..fe5c504 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -816,6 +816,15 @@ int usb_gadget_activate(struct usb_gadget *gadget)
}
EXPORT_SYMBOL_GPL(usb_gadget_activate);
+int usb_gadget_func_wakeup(struct usb_gadget *gadget, int interface_id)
+{
+ if (gadget->speed < USB_SPEED_SUPER || !gadget->ops->func_wakeup)
+ return -EOPNOTSUPP;
+
+ return gadget->ops->func_wakeup(gadget, interface_id);
+}
+EXPORT_SYMBOL_GPL(usb_gadget_func_wakeup);
+
/* ------------------------------------------------------------------------- */
#ifdef CONFIG_HAS_DMA
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 9d27622..31b35d7 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -254,6 +254,7 @@ int config_ep_by_speed_and_alt(struct usb_gadget *g, struct usb_function *f,
int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
struct usb_ep *_ep);
+int usb_func_wakeup(struct usb_function *func);
#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 3ad58b7..76f9de4 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -311,6 +311,7 @@ struct usb_udc;
struct usb_gadget_ops {
int (*get_frame)(struct usb_gadget *);
int (*wakeup)(struct usb_gadget *);
+ int (*func_wakeup)(struct usb_gadget *gadget, int interface_id);
int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
int (*vbus_session) (struct usb_gadget *, int is_active);
int (*vbus_draw) (struct usb_gadget *, unsigned mA);
@@ -612,6 +613,7 @@ int usb_gadget_disconnect(struct usb_gadget *gadget);
int usb_gadget_deactivate(struct usb_gadget *gadget);
int usb_gadget_activate(struct usb_gadget *gadget);
int usb_gadget_check_config(struct usb_gadget *gadget);
+int usb_gadget_func_wakeup(struct usb_gadget *gadget, int interface_id);
#else
static inline int usb_gadget_frame_number(struct usb_gadget *gadget)
{ return 0; }