Add the hooks that designer can design and bypass the original suspend/resume. When the handled is set, skip the original suspend/resume process. In mobile, a co-processor can be used for USB audio. When the co-processor is working for USB audio, the co-processor is the user/owner of the USB driver, and the ACPU is able to sleep in such condition to improve power consumption. In original process, the ACPU will suspend/resume until the USB suspend/resume. We add the hooks, so we can control USB suspend/resume without affecting the ACPU. Signed-off-by: Puma Hsu <pumahsu@xxxxxxxxxx> --- Changes in v2: - Remove the wrong input in the Makefile - Change description in commit message --- drivers/usb/core/driver.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/usb/core/usb.h | 5 +++++ 2 files changed, 41 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 7e7e119c253f..3d2cfb6c2277 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -35,6 +35,25 @@ #include "usb.h" +static struct usb_device_vendor_ops *usb_dev_vendor_ops; + +int usb_dev_register_vendor_ops(struct usb_device_vendor_ops *vendor_ops) +{ + if (vendor_ops == NULL) + return -EINVAL; + + usb_dev_vendor_ops = vendor_ops; + return 0; +} +EXPORT_SYMBOL_GPL(usb_dev_register_vendor_ops); + +struct usb_device_vendor_ops *usb_vendor_get_ops(void) +{ + return usb_dev_vendor_ops; +} +EXPORT_SYMBOL_GPL(usb_vendor_get_ops); + + /* * Adds a new dynamic USBdevice ID to this driver, * and cause the driver to probe for all devices again. @@ -1400,11 +1419,19 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) int status = 0; int i = 0, n = 0; struct usb_interface *intf; + bool handled; + struct usb_device_vendor_ops *ops = usb_vendor_get_ops(); if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED) goto done; + if (ops && ops->usb_dev_suspend) { + handled = ops->usb_dev_suspend(udev, msg); + if (handled) + goto done; + } + /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { n = udev->actconfig->desc.bNumInterfaces; @@ -1501,11 +1528,20 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) int status = 0; int i; struct usb_interface *intf; + bool handled; + struct usb_device_vendor_ops *ops = usb_vendor_get_ops(); if (udev->state == USB_STATE_NOTATTACHED) { status = -ENODEV; goto done; } + + if (ops && ops->usb_dev_resume) { + handled = ops->usb_dev_resume(udev, msg); + if (handled) + goto done; + } + udev->can_submit = 1; /* Resume the device */ diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 82538daac8b8..9ccb8683071d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -220,3 +220,8 @@ extern acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev, static inline int usb_acpi_register(void) { return 0; }; static inline void usb_acpi_unregister(void) { }; #endif + +struct usb_device_vendor_ops { + bool (*usb_dev_suspend)(struct usb_device *udev, pm_message_t msg); + bool (*usb_dev_resume)(struct usb_device *udev, pm_message_t msg); +}; -- 2.39.0.rc1.256.g54fd8350bd-goog