Skip to content

Update autosuspend\_check to prevent external USB mouse from auto-sus… #1257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 69 additions & 58 deletions drivers/usb/core/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1886,66 +1886,77 @@ void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);

/* Internal routine to check whether we may autosuspend a device. */
/*
* Modification: Added check for HID mouse interfaces to prevent autosuspend.
* Problem: External mouse experiences frequent/permanent autosuspend and non-smooth movement.
* Solution: Return -EBUSY when a HID mouse interface is found to block autosuspend.
*/
static int autosuspend_check(struct usb_device *udev)
{
int w, i;
struct usb_interface *intf;

if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;

/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
*/
w = 0;
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];

/* We don't need to check interfaces that are
* disabled for runtime PM. Either they are unbound
* or else their drivers don't support autosuspend
* and so they are permanently active.
*/
if (intf->dev.power.disable_depth)
continue;
if (atomic_read(&intf->dev.power.usage_count) > 0)
return -EBUSY;
w |= intf->needs_remote_wakeup;

/* Don't allow autosuspend if the device will need
* a reset-resume and any of its interface drivers
* doesn't include support or needs remote wakeup.
*/
if (udev->quirks & USB_QUIRK_RESET_RESUME) {
struct usb_driver *driver;

driver = to_usb_driver(intf->dev.driver);
if (!driver->reset_resume ||
intf->needs_remote_wakeup)
return -EOPNOTSUPP;
}
}
}
if (w && !device_can_wakeup(&udev->dev)) {
dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
return -EOPNOTSUPP;
}

/*
* If the device is a direct child of the root hub and the HCD
* doesn't handle wakeup requests, don't allow autosuspend when
* wakeup is needed.
*/
if (w && udev->parent == udev->bus->root_hub &&
bus_to_hcd(udev->bus)->cant_recv_wakeups) {
dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
return -EOPNOTSUPP;
}

udev->do_remote_wakeup = w;
return 0;
int w, i;
struct usb_interface *intf;

if (udev->state == USB_STATE_NOTATTACHED)
return -ENODEV;

/* Fail if autosuspend is disabled, or any interfaces are in use, or
* any interface drivers require remote wakeup but it isn't available.
*/
w = 0;
if (udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];

/* don't need to check interfaces that are
* disabled for runtime PM. Either they are unbound
* or else their drivers don't support autosuspend
* and so they are permanently active.
*/
if (intf->dev.power.disable_depth)
continue;
if (atomic_read(&intf->dev.power.usage_count) > 0)
return -EBUSY;
w |= intf->needs_remote_wakeup;

/* Don't allow autosuspend if the device will need
* a reset-resume and any of its interface drivers
* doesn't include support or needs remote wakeup.
*/
if (udev->quirks & USB_QUIRK_RESET_RESUME) {
struct usb_driver *driver;

driver = to_usb_driver(intf->dev.driver);
if (!driver->reset_resume ||
intf->needs_remote_wakeup)
return -EOPNOTSUPP;
}

/* Begin change: Prevent autosuspend for HID mouse interfaces */
if (intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_HID &&
intf->cur_altsetting->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) {
return -EBUSY;
}
/* End change */
}
}
if (w && !device_can_wakeup(&udev->dev)) {
dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
return -EOPNOTSUPP;
}

/*
* If the device is a direct child of the root hub and the HCD
* doesn't handle wakeup requests, don't allow autosuspend when
* wakeup is needed.
*/
if (w && udev->parent == udev->bus->root_hub &&
bus_to_hcd(udev->bus)->cant_recv_wakeups) {
dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
return -EOPNOTSUPP;
}

udev->do_remote_wakeup = w;
return 0;
}

int usb_runtime_suspend(struct device *dev)
Expand Down