diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 8da1a56659be48e789d47f328d83a591e99e1160..ddb54e14a5c54595908b4773f125db97c3e550e5 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -201,6 +201,7 @@ static int usb_probe_interface(struct device *dev)
 
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
+	intf->needs_binding = 0;
 
 	if (udev->authorized == 0) {
 		dev_err(&intf->dev, "Device is not authorized for usage\n");
@@ -311,6 +312,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 
 	dev->driver = &driver->drvwrap.driver;
 	usb_set_intfdata(iface, priv);
+	iface->needs_binding = 0;
 
 	usb_pm_lock(udev);
 	iface->condition = USB_INTERFACE_BOUND;
@@ -772,6 +774,104 @@ void usb_deregister(struct usb_driver *driver)
 }
 EXPORT_SYMBOL_GPL(usb_deregister);
 
+
+/* Forced unbinding of a USB interface driver, either because
+ * it doesn't support pre_reset/post_reset/reset_resume or
+ * because it doesn't support suspend/resume.
+ *
+ * The caller must hold @intf's device's lock, but not its pm_mutex
+ * and not @intf->dev.sem.
+ */
+void usb_forced_unbind_intf(struct usb_interface *intf)
+{
+	struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+
+	dev_dbg(&intf->dev, "forced unbind\n");
+	usb_driver_release_interface(driver, intf);
+
+	/* Mark the interface for later rebinding */
+	intf->needs_binding = 1;
+}
+
+/* Delayed forced unbinding of a USB interface driver and scan
+ * for rebinding.
+ *
+ * The caller must hold @intf's device's lock, but not its pm_mutex
+ * and not @intf->dev.sem.
+ *
+ * FIXME: The caller must block system sleep transitions.
+ */
+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);
+	}
+
+	/* Try to rebind the interface */
+	intf->needs_binding = 0;
+	rc = device_attach(&intf->dev);
+	if (rc < 0)
+		dev_warn(&intf->dev, "rebind failed: %d\n", rc);
+}
+
+#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.
+ *
+ * The caller must hold @udev's device lock.
+ * FIXME: For rebinds, the caller must block system sleep transitions.
+ */
+static void do_unbind_rebind(struct usb_device *udev, int action)
+{
+	struct usb_host_config	*config;
+	int			i;
+	struct usb_interface	*intf;
+	struct usb_driver	*drv;
+
+	config = udev->actconfig;
+	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:
+				if (intf->needs_binding) {
+
+	/* FIXME: The next line is needed because we are going to probe
+	 * the interface, but as far as the PM core is concerned the
+	 * interface is still suspended.  The problem wouldn't exist
+	 * if we could rebind the interface during the interface's own
+	 * resume() call, but at the time the usb_device isn't locked!
+	 *
+	 * The real solution will be to carry this out during the device's
+	 * complete() callback.  Until that is implemented, we have to
+	 * use this hack.
+	 */
+//					intf->dev.power.sleeping = 0;
+
+					usb_rebind_intf(intf);
+				}
+				break;
+			}
+		}
+	}
+}
+
 #ifdef CONFIG_PM
 
 /* Caller has locked udev's pm_mutex */
@@ -841,7 +941,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
 		goto done;
 	driver = to_usb_driver(intf->dev.driver);
 
-	if (driver->suspend && driver->resume) {
+	if (driver->suspend) {
 		status = driver->suspend(intf, msg);
 		if (status == 0)
 			mark_quiesced(intf);
@@ -849,12 +949,10 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
 			dev_err(&intf->dev, "%s error %d\n",
 					"suspend", status);
 	} else {
-		/*
-		 * FIXME else if there's no suspend method, disconnect...
-		 * Not possible if auto_pm is set...
-		 */
-		dev_warn(&intf->dev, "no suspend for driver %s?\n",
-				driver->name);
+		/* Later we will unbind the driver and reprobe */
+		intf->needs_binding = 1;
+		dev_warn(&intf->dev, "no %s for driver %s?\n",
+				"suspend", driver->name);
 		mark_quiesced(intf);
 	}
 
@@ -878,10 +976,12 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 		goto done;
 
 	/* Can't resume it if it doesn't have a driver. */
-	if (intf->condition == USB_INTERFACE_UNBOUND) {
-		status = -ENOTCONN;
+	if (intf->condition == USB_INTERFACE_UNBOUND)
+		goto done;
+
+	/* Don't resume if the interface is marked for rebinding */
+	if (intf->needs_binding)
 		goto done;
-	}
 	driver = to_usb_driver(intf->dev.driver);
 
 	if (reset_resume) {
@@ -891,7 +991,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 				dev_err(&intf->dev, "%s error %d\n",
 						"reset_resume", status);
 		} else {
-			/* status = -EOPNOTSUPP; */
+			intf->needs_binding = 1;
 			dev_warn(&intf->dev, "no %s for driver %s?\n",
 					"reset_resume", driver->name);
 		}
@@ -902,7 +1002,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 				dev_err(&intf->dev, "%s error %d\n",
 						"resume", status);
 		} else {
-			/* status = -EOPNOTSUPP; */
+			intf->needs_binding = 1;
 			dev_warn(&intf->dev, "no %s for driver %s?\n",
 					"resume", driver->name);
 		}
@@ -910,11 +1010,10 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 
 done:
 	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
-	if (status == 0)
+	if (status == 0 && intf->condition == USB_INTERFACE_BOUND)
 		mark_active(intf);
 
-	/* FIXME: Unbind the driver and reprobe if the resume failed
-	 * (not possible if auto_pm is set) */
+	/* Later we will unbind the driver and/or reprobe, if necessary */
 	return status;
 }
 
@@ -1470,6 +1569,7 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
 	int	status;
 
+	do_unbind_rebind(udev, DO_UNBIND);
 	usb_pm_lock(udev);
 	udev->auto_pm = 0;
 	status = usb_suspend_both(udev, msg);
@@ -1497,6 +1597,7 @@ int usb_external_resume_device(struct usb_device *udev)
 	status = usb_resume_both(udev);
 	udev->last_busy = jiffies;
 	usb_pm_unlock(udev);
+	do_unbind_rebind(udev, DO_REBIND);
 
 	/* Now that the device is awake, we can start trying to autosuspend
 	 * it again. */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index bb3ecc4c08f223c1741ea9d6ca922c01baaaf621..f1efabbc1ca22d85c5fca99f59b40c93185beab2 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3367,6 +3367,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
  * the device using usb_lock_device_for_reset().
+ *
+ * If an interface is currently being probed or disconnected, we assume
+ * its driver knows how to handle resets.  For all other interfaces,
+ * if the driver doesn't have pre_reset and post_reset methods then
+ * we attempt to unbind it and rebind afterward.
  */
 int usb_reset_device(struct usb_device *udev)
 {
@@ -3388,12 +3393,17 @@ int usb_reset_device(struct usb_device *udev)
 		for (i = 0; i < config->desc.bNumInterfaces; ++i) {
 			struct usb_interface *cintf = config->interface[i];
 			struct usb_driver *drv;
+			int unbind = 0;
 
 			if (cintf->dev.driver) {
 				drv = to_usb_driver(cintf->dev.driver);
-				if (drv->pre_reset)
-					(drv->pre_reset)(cintf);
-	/* FIXME: Unbind if pre_reset returns an error or isn't defined */
+				if (drv->pre_reset && drv->post_reset)
+					unbind = (drv->pre_reset)(cintf);
+				else if (cintf->condition ==
+						USB_INTERFACE_BOUND)
+					unbind = 1;
+				if (unbind)
+					usb_forced_unbind_intf(cintf);
 			}
 		}
 	}
@@ -3404,13 +3414,18 @@ int usb_reset_device(struct usb_device *udev)
 		for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
 			struct usb_interface *cintf = config->interface[i];
 			struct usb_driver *drv;
+			int rebind = cintf->needs_binding;
 
-			if (cintf->dev.driver) {
+			if (!rebind && cintf->dev.driver) {
 				drv = to_usb_driver(cintf->dev.driver);
 				if (drv->post_reset)
-					(drv->post_reset)(cintf);
-	/* FIXME: Unbind if post_reset returns an error or isn't defined */
+					rebind = (drv->post_reset)(cintf);
+				else if (cintf->condition ==
+						USB_INTERFACE_BOUND)
+					rebind = 1;
 			}
+			if (rebind)
+				usb_rebind_intf(cintf);
 		}
 	}
 
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 1a8bc21c335e8848ebe5c2c1947fd5c0c38cd775..d3eb0a29bca1f7fb87f890d3a36431795a67ecc9 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -29,6 +29,8 @@ extern int usb_choose_configuration(struct usb_device *udev);
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
 			    const struct usb_device_id *id);
+extern void usb_forced_unbind_intf(struct usb_interface *intf);
+extern void usb_rebind_intf(struct usb_interface *intf);
 
 extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 3cc8db5254d1d7fc7e01d4736cddf585a361c203..5811c5da69f938275e4ba595a23fc252b4c0fc1a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -160,6 +160,7 @@ struct usb_interface {
 	unsigned is_active:1;		/* the interface is not suspended */
 	unsigned sysfs_files_created:1;	/* the sysfs attributes exist */
 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
+	unsigned needs_binding:1;	/* needs delayed unbind/rebind */
 
 	struct device dev;		/* interface specific device info */
 	struct device *usb_dev;