Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1493138a authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman
Browse files

USB: code cleanup in suspend/resume path (3rd try)



Do the cleanup to avoid behaviorial parameters Linus
requested.

Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dcd6c922
Loading
Loading
Loading
Loading
+63 −30
Original line number Diff line number Diff line
@@ -958,13 +958,8 @@ void usb_rebind_intf(struct usb_interface *intf)
	int rc;

	/* Delayed unbind of an existing driver */
	if (intf->dev.driver) {
		struct usb_driver *driver =
				to_usb_driver(intf->dev.driver);

		dev_dbg(&intf->dev, "forced unbind\n");
		usb_driver_release_interface(driver, intf);
	}
	if (intf->dev.driver)
		usb_forced_unbind_intf(intf);

	/* Try to rebind the interface */
	if (!intf->dev.power.is_prepared) {
@@ -977,15 +972,13 @@ void usb_rebind_intf(struct usb_interface *intf)

#ifdef CONFIG_PM

#define DO_UNBIND	0
#define DO_REBIND	1

/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
 * or rebind interfaces that have been unbound, according to @action.
/* Unbind drivers for @udev's interfaces that don't support suspend/resume
 * There is no check for reset_resume here because it can be determined
 * only during resume whether reset_resume is needed.
 *
 * The caller must hold @udev's device lock.
 */
static void do_unbind_rebind(struct usb_device *udev, int action)
static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
{
	struct usb_host_config	*config;
	int			i;
@@ -996,19 +989,49 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
	if (config) {
		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
			intf = config->interface[i];
			switch (action) {
			case DO_UNBIND:

			if (intf->dev.driver) {
				drv = to_usb_driver(intf->dev.driver);
				if (!drv->suspend || !drv->resume)
					usb_forced_unbind_intf(intf);
			}
				break;
			case DO_REBIND:
		}
	}
}

/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
 * These interfaces have the needs_binding flag set by usb_resume_interface().
 *
 * The caller must hold @udev's device lock.
 */
static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
{
	struct usb_host_config	*config;
	int			i;
	struct usb_interface	*intf;

	config = udev->actconfig;
	if (config) {
		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
			intf = config->interface[i];
			if (intf->dev.driver && intf->needs_binding)
				usb_forced_unbind_intf(intf);
		}
	}
}

static void do_rebind_interfaces(struct usb_device *udev)
{
	struct usb_host_config	*config;
	int			i;
	struct usb_interface	*intf;

	config = udev->actconfig;
	if (config) {
		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
			intf = config->interface[i];
			if (intf->needs_binding)
				usb_rebind_intf(intf);
				break;
			}
		}
	}
}
@@ -1302,7 +1325,12 @@ int usb_suspend(struct device *dev, pm_message_t msg)
{
	struct usb_device	*udev = to_usb_device(dev);

	do_unbind_rebind(udev, DO_UNBIND);
	unbind_no_pm_drivers_interfaces(udev);

	/* From now on we are sure all drivers support suspend/resume
	 * but not necessarily reset_resume()
	 * so we may still need to unbind and rebind upon resume
	 */
	choose_wakeup(udev, msg);
	return usb_suspend_both(udev, msg);
}
@@ -1313,15 +1341,20 @@ int usb_resume(struct device *dev, pm_message_t msg)
	struct usb_device	*udev = to_usb_device(dev);
	int			status;

	/* For PM complete calls, all we do is rebind interfaces */
	/* For PM complete calls, all we do is rebind interfaces
	 * whose needs_binding flag is set
	 */
	if (msg.event == PM_EVENT_ON) {
		if (udev->state != USB_STATE_NOTATTACHED)
			do_unbind_rebind(udev, DO_REBIND);
			do_rebind_interfaces(udev);
		status = 0;

	/* For all other calls, take the device back to full power and
	 * tell the PM core in case it was autosuspended previously.
	 * Unbind the interfaces that will need rebinding later.
	 * Unbind the interfaces that will need rebinding later,
	 * because they fail to support reset_resume.
	 * (This can't be done in usb_resume_interface()
         * above because it doesn't own the right set of locks.)
	 */
	} else {
		status = usb_resume_both(udev, msg);
@@ -1329,7 +1362,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
			pm_runtime_disable(dev);
			pm_runtime_set_active(dev);
			pm_runtime_enable(dev);
			do_unbind_rebind(udev, DO_REBIND);
			unbind_no_reset_resume_drivers_interfaces(udev);
		}
	}