On 3/16/2023 5:11 PM, Thinh Nguyen wrote:
On Thu, Mar 16, 2023, Elson Roy Serrao wrote:
When host sends a suspend notification to the device, handle
the suspend callbacks in the function driver. Enhanced super
speed devices can support function suspend feature to put the
function in suspend state. Handle function suspend callback.
Depending on the remote wakeup capability the device can either
trigger a remote wakeup or wait for the host initiated resume to
start data transfer again.
Signed-off-by: Elson Roy Serrao <quic_eserrao@xxxxxxxxxxx>
---
drivers/usb/gadget/function/f_ecm.c | 71 +++++++++++++++++++++++++++++++++++
drivers/usb/gadget/function/u_ether.c | 63 +++++++++++++++++++++++++++++++
drivers/usb/gadget/function/u_ether.h | 4 ++
3 files changed, 138 insertions(+)
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index a7ab30e..c43cd557 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -633,6 +633,8 @@ static void ecm_disable(struct usb_function *f)
usb_ep_disable(ecm->notify);
ecm->notify->desc = NULL;
+ f->func_suspended = false;
+ f->func_wakeup_armed = false;
}
/*-------------------------------------------------------------------------*/
@@ -885,6 +887,71 @@ static struct usb_function_instance *ecm_alloc_inst(void)
return &opts->func_inst;
}
+static void ecm_suspend(struct usb_function *f)
+{
+ struct f_ecm *ecm = func_to_ecm(f);
+ struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
+
+ if (f->func_suspended) {
+ DBG(cdev, "Function already suspended\n");
+ return;
+ }
+
+ DBG(cdev, "ECM Suspend\n");
+
+ gether_suspend(&ecm->port);
+}
+
+static void ecm_resume(struct usb_function *f)
+{
+ struct f_ecm *ecm = func_to_ecm(f);
+ struct usb_composite_dev *cdev = ecm->port.func.config->cdev;
+
+ /*
+ * If the function is in USB3 Function Suspend state, resume is
+ * canceled. In this case resume is done by a Function Resume request.
+ */
+ if (f->func_suspended)
+ return;
+
+ DBG(cdev, "ECM Resume\n");
+
+ gether_resume(&ecm->port);
+}
+
+static int ecm_get_status(struct usb_function *f)
+{
+ struct usb_configuration *c = f->config;
+
+ /* D0 and D1 bit set to 0 if device is not wakeup capable */
+ if (!(USB_CONFIG_ATT_WAKEUP & c->bmAttributes))
+ return 0;
+
+ return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) |
+ USB_INTRF_STAT_FUNC_RW_CAP;
+}
Why do we need to implement ecm_get_status if it's already handled in
composite.c now?
Yes this can be removed now. Will modify accordingly.
+
+static int ecm_func_suspend(struct usb_function *f, u8 options)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ DBG(cdev, "func susp %u cmd\n", options);
+
+ if (options & (USB_INTRF_FUNC_SUSPEND_LP >> 8)) {
This feature selector doesn't indicate whether it's SetFeature or
ClearFeature request. ecm_func_suspend is supposed to be for
SetFeature(suspend) only. Perhaps we may have to define func_resume()
for ClearFeature(suspend)?
Thanks,
Thinh
Host uses the same feature selector FUNCTION_SUSPEND for function
suspend and function resume and func_suspend() callback can be used to
handle both the cases ? The distinction comes whether it is a
SetFeature(FUNCTION_SUSPEND) or ClearFeature(FUNCTION_SUSPEND) which can
be easily done in the func_suspend callback itself. We can add another
callback func_resume specific to ClearFeature(FUNCTION_SUSPEND) but wont
that be redundant and more callback handling on function
driver/composite side as well? Please let me know your opinion.
Thanks
Elson
+ if (!f->func_suspended) {
+ ecm_suspend(f);
+ f->func_suspended = true;
+ }
+ } else {
+ if (f->func_suspended) {
+ f->func_suspended = false;
+ ecm_resume(f);
+ }
+ }
+
+ return 0;
+}
+