Merge branch 'writeback' of git://git.kernel.dk/linux-2.6-block
[pandora-kernel.git] / drivers / usb / core / driver.c
index 69e5773..4f86447 100644 (file)
@@ -207,6 +207,9 @@ static int usb_probe_interface(struct device *dev)
 
        intf->needs_binding = 0;
 
+       if (usb_device_is_owned(udev))
+               return -ENODEV;
+
        if (udev->authorized == 0) {
                dev_err(&intf->dev, "Device is not authorized for usage\n");
                return -ENODEV;
@@ -232,28 +235,35 @@ static int usb_probe_interface(struct device *dev)
                /* The interface should always appear to be in use
                 * unless the driver suports autosuspend.
                 */
-               intf->pm_usage_cnt = !(driver->supports_autosuspend);
+               atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
 
                /* Carry out a deferred switch to altsetting 0 */
                if (intf->needs_altsetting0) {
-                       usb_set_interface(udev, intf->altsetting[0].
+                       error = usb_set_interface(udev, intf->altsetting[0].
                                        desc.bInterfaceNumber, 0);
+                       if (error < 0)
+                               goto err;
+
                        intf->needs_altsetting0 = 0;
                }
 
                error = driver->probe(intf, id);
-               if (error) {
-                       mark_quiesced(intf);
-                       intf->needs_remote_wakeup = 0;
-                       intf->condition = USB_INTERFACE_UNBOUND;
-                       usb_cancel_queued_reset(intf);
-               } else
-                       intf->condition = USB_INTERFACE_BOUND;
+               if (error)
+                       goto err;
 
+               intf->condition = USB_INTERFACE_BOUND;
                usb_autosuspend_device(udev);
        }
 
        return error;
+
+err:
+       mark_quiesced(intf);
+       intf->needs_remote_wakeup = 0;
+       intf->condition = USB_INTERFACE_UNBOUND;
+       usb_cancel_queued_reset(intf);
+       usb_autosuspend_device(udev);
+       return error;
 }
 
 /* called from driver core with dev locked */
@@ -262,7 +272,7 @@ static int usb_unbind_interface(struct device *dev)
        struct usb_driver *driver = to_usb_driver(dev->driver);
        struct usb_interface *intf = to_usb_interface(dev);
        struct usb_device *udev;
-       int error;
+       int error, r;
 
        intf->condition = USB_INTERFACE_UNBINDING;
 
@@ -290,11 +300,14 @@ static int usb_unbind_interface(struct device *dev)
                 * Just re-enable it without affecting the endpoint toggles.
                 */
                usb_enable_interface(udev, intf, false);
-       } else if (!error && intf->dev.power.status == DPM_ON)
-               usb_set_interface(udev, intf->altsetting[0].
+       } else if (!error && intf->dev.power.status == DPM_ON) {
+               r = usb_set_interface(udev, intf->altsetting[0].
                                desc.bInterfaceNumber, 0);
-       else
+               if (r < 0)
+                       intf->needs_altsetting0 = 1;
+       } else {
                intf->needs_altsetting0 = 1;
+       }
        usb_set_intfdata(intf, NULL);
 
        intf->condition = USB_INTERFACE_UNBOUND;
@@ -344,7 +357,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
        usb_pm_lock(udev);
        iface->condition = USB_INTERFACE_BOUND;
        mark_active(iface);
-       iface->pm_usage_cnt = !(driver->supports_autosuspend);
+       atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
        usb_pm_unlock(udev);
 
        /* if interface was already added, bind now; else let
@@ -1065,7 +1078,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
                        intf = udev->actconfig->interface[i];
                        if (!is_active(intf))
                                continue;
-                       if (intf->pm_usage_cnt > 0)
+                       if (atomic_read(&intf->pm_usage_cnt) > 0)
                                return -EBUSY;
                        if (intf->needs_remote_wakeup &&
                                        !udev->do_remote_wakeup) {
@@ -1461,17 +1474,19 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
                status = -ENODEV;
        else {
                udev->auto_pm = 1;
-               intf->pm_usage_cnt += inc_usage_cnt;
+               atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
                udev->last_busy = jiffies;
-               if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
+               if (inc_usage_cnt >= 0 &&
+                               atomic_read(&intf->pm_usage_cnt) > 0) {
                        if (udev->state == USB_STATE_SUSPENDED)
                                status = usb_resume_both(udev,
                                                PMSG_AUTO_RESUME);
                        if (status != 0)
-                               intf->pm_usage_cnt -= inc_usage_cnt;
+                               atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
                        else
                                udev->last_busy = jiffies;
-               } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
+               } else if (inc_usage_cnt <= 0 &&
+                               atomic_read(&intf->pm_usage_cnt) <= 0) {
                        status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
                }
        }
@@ -1516,7 +1531,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
 
        status = usb_autopm_do_interface(intf, -1);
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __func__, status, intf->pm_usage_cnt);
+                       __func__, status, atomic_read(&intf->pm_usage_cnt));
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 
@@ -1544,10 +1559,10 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
                status = -ENODEV;
        } else {
                udev->last_busy = jiffies;
-               --intf->pm_usage_cnt;
+               atomic_dec(&intf->pm_usage_cnt);
                if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
                        status = -EPERM;
-               else if (intf->pm_usage_cnt <= 0 &&
+               else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
                                !timer_pending(&udev->autosuspend.timer)) {
                        queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
                                        round_jiffies_up_relative(
@@ -1555,7 +1570,7 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
                }
        }
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __func__, status, intf->pm_usage_cnt);
+                       __func__, status, atomic_read(&intf->pm_usage_cnt));
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
 
@@ -1599,7 +1614,7 @@ int usb_autopm_get_interface(struct usb_interface *intf)
 
        status = usb_autopm_do_interface(intf, 1);
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __func__, status, intf->pm_usage_cnt);
+                       __func__, status, atomic_read(&intf->pm_usage_cnt));
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1627,10 +1642,14 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
                status = -ENODEV;
        else if (udev->autoresume_disabled)
                status = -EPERM;
-       else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
-               queue_work(ksuspend_usb_wq, &udev->autoresume);
+       else {
+               atomic_inc(&intf->pm_usage_cnt);
+               if (atomic_read(&intf->pm_usage_cnt) > 0 &&
+                               udev->state == USB_STATE_SUSPENDED)
+                       queue_work(ksuspend_usb_wq, &udev->autoresume);
+       }
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __func__, status, intf->pm_usage_cnt);
+                       __func__, status, atomic_read(&intf->pm_usage_cnt));
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
@@ -1652,7 +1671,7 @@ int usb_autopm_set_interface(struct usb_interface *intf)
 
        status = usb_autopm_do_interface(intf, 0);
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __func__, status, intf->pm_usage_cnt);
+                       __func__, status, atomic_read(&intf->pm_usage_cnt));
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_set_interface);