USB: usb_driver_claim_interface: add sanity checking
[pandora-kernel.git] / drivers / usb / core / driver.c
index 9f3003e..c595714 100644 (file)
@@ -428,9 +428,13 @@ static int usb_unbind_interface(struct device *dev)
 int usb_driver_claim_interface(struct usb_driver *driver,
                                struct usb_interface *iface, void *priv)
 {
-       struct device *dev = &iface->dev;
+       struct device *dev;
        int retval = 0;
 
+       if (!iface)
+               return -ENODEV;
+
+       dev = &iface->dev;
        if (dev->driver)
                return -EBUSY;
 
@@ -1664,6 +1668,18 @@ static int autosuspend_check(struct usb_device *udev)
                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;
 }
@@ -1686,10 +1702,13 @@ int usb_runtime_suspend(struct device *dev)
        if (status == -EAGAIN || status == -EBUSY)
                usb_mark_last_busy(udev);
 
-       /* The PM core reacts badly unless the return code is 0,
-        * -EAGAIN, or -EBUSY, so always return -EBUSY on an error.
+       /*
+        * The PM core reacts badly unless the return code is 0,
+        * -EAGAIN, or -EBUSY, so always return -EBUSY on an error
+        * (except for root hubs, because they don't suspend through
+        * an upstream port like other USB devices).
         */
-       if (status != 0)
+       if (status != 0 && udev->parent)
                return -EBUSY;
        return status;
 }