diff options
Diffstat (limited to 'drivers/usb/core/driver.c')
-rw-r--r-- | drivers/usb/core/driver.c | 75 |
1 files changed, 47 insertions, 28 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 69e5773abfce..4f864472c5c4 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c | |||
@@ -207,6 +207,9 @@ static int usb_probe_interface(struct device *dev) | |||
207 | 207 | ||
208 | intf->needs_binding = 0; | 208 | intf->needs_binding = 0; |
209 | 209 | ||
210 | if (usb_device_is_owned(udev)) | ||
211 | return -ENODEV; | ||
212 | |||
210 | if (udev->authorized == 0) { | 213 | if (udev->authorized == 0) { |
211 | dev_err(&intf->dev, "Device is not authorized for usage\n"); | 214 | dev_err(&intf->dev, "Device is not authorized for usage\n"); |
212 | return -ENODEV; | 215 | return -ENODEV; |
@@ -232,28 +235,35 @@ static int usb_probe_interface(struct device *dev) | |||
232 | /* The interface should always appear to be in use | 235 | /* The interface should always appear to be in use |
233 | * unless the driver suports autosuspend. | 236 | * unless the driver suports autosuspend. |
234 | */ | 237 | */ |
235 | intf->pm_usage_cnt = !(driver->supports_autosuspend); | 238 | atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend); |
236 | 239 | ||
237 | /* Carry out a deferred switch to altsetting 0 */ | 240 | /* Carry out a deferred switch to altsetting 0 */ |
238 | if (intf->needs_altsetting0) { | 241 | if (intf->needs_altsetting0) { |
239 | usb_set_interface(udev, intf->altsetting[0]. | 242 | error = usb_set_interface(udev, intf->altsetting[0]. |
240 | desc.bInterfaceNumber, 0); | 243 | desc.bInterfaceNumber, 0); |
244 | if (error < 0) | ||
245 | goto err; | ||
246 | |||
241 | intf->needs_altsetting0 = 0; | 247 | intf->needs_altsetting0 = 0; |
242 | } | 248 | } |
243 | 249 | ||
244 | error = driver->probe(intf, id); | 250 | error = driver->probe(intf, id); |
245 | if (error) { | 251 | if (error) |
246 | mark_quiesced(intf); | 252 | goto err; |
247 | intf->needs_remote_wakeup = 0; | ||
248 | intf->condition = USB_INTERFACE_UNBOUND; | ||
249 | usb_cancel_queued_reset(intf); | ||
250 | } else | ||
251 | intf->condition = USB_INTERFACE_BOUND; | ||
252 | 253 | ||
254 | intf->condition = USB_INTERFACE_BOUND; | ||
253 | usb_autosuspend_device(udev); | 255 | usb_autosuspend_device(udev); |
254 | } | 256 | } |
255 | 257 | ||
256 | return error; | 258 | return error; |
259 | |||
260 | err: | ||
261 | mark_quiesced(intf); | ||
262 | intf->needs_remote_wakeup = 0; | ||
263 | intf->condition = USB_INTERFACE_UNBOUND; | ||
264 | usb_cancel_queued_reset(intf); | ||
265 | usb_autosuspend_device(udev); | ||
266 | return error; | ||
257 | } | 267 | } |
258 | 268 | ||
259 | /* called from driver core with dev locked */ | 269 | /* called from driver core with dev locked */ |
@@ -262,7 +272,7 @@ static int usb_unbind_interface(struct device *dev) | |||
262 | struct usb_driver *driver = to_usb_driver(dev->driver); | 272 | struct usb_driver *driver = to_usb_driver(dev->driver); |
263 | struct usb_interface *intf = to_usb_interface(dev); | 273 | struct usb_interface *intf = to_usb_interface(dev); |
264 | struct usb_device *udev; | 274 | struct usb_device *udev; |
265 | int error; | 275 | int error, r; |
266 | 276 | ||
267 | intf->condition = USB_INTERFACE_UNBINDING; | 277 | intf->condition = USB_INTERFACE_UNBINDING; |
268 | 278 | ||
@@ -290,11 +300,14 @@ static int usb_unbind_interface(struct device *dev) | |||
290 | * Just re-enable it without affecting the endpoint toggles. | 300 | * Just re-enable it without affecting the endpoint toggles. |
291 | */ | 301 | */ |
292 | usb_enable_interface(udev, intf, false); | 302 | usb_enable_interface(udev, intf, false); |
293 | } else if (!error && intf->dev.power.status == DPM_ON) | 303 | } else if (!error && intf->dev.power.status == DPM_ON) { |
294 | usb_set_interface(udev, intf->altsetting[0]. | 304 | r = usb_set_interface(udev, intf->altsetting[0]. |
295 | desc.bInterfaceNumber, 0); | 305 | desc.bInterfaceNumber, 0); |
296 | else | 306 | if (r < 0) |
307 | intf->needs_altsetting0 = 1; | ||
308 | } else { | ||
297 | intf->needs_altsetting0 = 1; | 309 | intf->needs_altsetting0 = 1; |
310 | } | ||
298 | usb_set_intfdata(intf, NULL); | 311 | usb_set_intfdata(intf, NULL); |
299 | 312 | ||
300 | intf->condition = USB_INTERFACE_UNBOUND; | 313 | intf->condition = USB_INTERFACE_UNBOUND; |
@@ -344,7 +357,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, | |||
344 | usb_pm_lock(udev); | 357 | usb_pm_lock(udev); |
345 | iface->condition = USB_INTERFACE_BOUND; | 358 | iface->condition = USB_INTERFACE_BOUND; |
346 | mark_active(iface); | 359 | mark_active(iface); |
347 | iface->pm_usage_cnt = !(driver->supports_autosuspend); | 360 | atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend); |
348 | usb_pm_unlock(udev); | 361 | usb_pm_unlock(udev); |
349 | 362 | ||
350 | /* if interface was already added, bind now; else let | 363 | /* if interface was already added, bind now; else let |
@@ -1065,7 +1078,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule) | |||
1065 | intf = udev->actconfig->interface[i]; | 1078 | intf = udev->actconfig->interface[i]; |
1066 | if (!is_active(intf)) | 1079 | if (!is_active(intf)) |
1067 | continue; | 1080 | continue; |
1068 | if (intf->pm_usage_cnt > 0) | 1081 | if (atomic_read(&intf->pm_usage_cnt) > 0) |
1069 | return -EBUSY; | 1082 | return -EBUSY; |
1070 | if (intf->needs_remote_wakeup && | 1083 | if (intf->needs_remote_wakeup && |
1071 | !udev->do_remote_wakeup) { | 1084 | !udev->do_remote_wakeup) { |
@@ -1461,17 +1474,19 @@ static int usb_autopm_do_interface(struct usb_interface *intf, | |||
1461 | status = -ENODEV; | 1474 | status = -ENODEV; |
1462 | else { | 1475 | else { |
1463 | udev->auto_pm = 1; | 1476 | udev->auto_pm = 1; |
1464 | intf->pm_usage_cnt += inc_usage_cnt; | 1477 | atomic_add(inc_usage_cnt, &intf->pm_usage_cnt); |
1465 | udev->last_busy = jiffies; | 1478 | udev->last_busy = jiffies; |
1466 | if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { | 1479 | if (inc_usage_cnt >= 0 && |
1480 | atomic_read(&intf->pm_usage_cnt) > 0) { | ||
1467 | if (udev->state == USB_STATE_SUSPENDED) | 1481 | if (udev->state == USB_STATE_SUSPENDED) |
1468 | status = usb_resume_both(udev, | 1482 | status = usb_resume_both(udev, |
1469 | PMSG_AUTO_RESUME); | 1483 | PMSG_AUTO_RESUME); |
1470 | if (status != 0) | 1484 | if (status != 0) |
1471 | intf->pm_usage_cnt -= inc_usage_cnt; | 1485 | atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt); |
1472 | else | 1486 | else |
1473 | udev->last_busy = jiffies; | 1487 | udev->last_busy = jiffies; |
1474 | } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { | 1488 | } else if (inc_usage_cnt <= 0 && |
1489 | atomic_read(&intf->pm_usage_cnt) <= 0) { | ||
1475 | status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); | 1490 | status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); |
1476 | } | 1491 | } |
1477 | } | 1492 | } |
@@ -1516,7 +1531,7 @@ void usb_autopm_put_interface(struct usb_interface *intf) | |||
1516 | 1531 | ||
1517 | status = usb_autopm_do_interface(intf, -1); | 1532 | status = usb_autopm_do_interface(intf, -1); |
1518 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", | 1533 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", |
1519 | __func__, status, intf->pm_usage_cnt); | 1534 | __func__, status, atomic_read(&intf->pm_usage_cnt)); |
1520 | } | 1535 | } |
1521 | EXPORT_SYMBOL_GPL(usb_autopm_put_interface); | 1536 | EXPORT_SYMBOL_GPL(usb_autopm_put_interface); |
1522 | 1537 | ||
@@ -1544,10 +1559,10 @@ void usb_autopm_put_interface_async(struct usb_interface *intf) | |||
1544 | status = -ENODEV; | 1559 | status = -ENODEV; |
1545 | } else { | 1560 | } else { |
1546 | udev->last_busy = jiffies; | 1561 | udev->last_busy = jiffies; |
1547 | --intf->pm_usage_cnt; | 1562 | atomic_dec(&intf->pm_usage_cnt); |
1548 | if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) | 1563 | if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) |
1549 | status = -EPERM; | 1564 | status = -EPERM; |
1550 | else if (intf->pm_usage_cnt <= 0 && | 1565 | else if (atomic_read(&intf->pm_usage_cnt) <= 0 && |
1551 | !timer_pending(&udev->autosuspend.timer)) { | 1566 | !timer_pending(&udev->autosuspend.timer)) { |
1552 | queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, | 1567 | queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, |
1553 | round_jiffies_up_relative( | 1568 | round_jiffies_up_relative( |
@@ -1555,7 +1570,7 @@ void usb_autopm_put_interface_async(struct usb_interface *intf) | |||
1555 | } | 1570 | } |
1556 | } | 1571 | } |
1557 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", | 1572 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", |
1558 | __func__, status, intf->pm_usage_cnt); | 1573 | __func__, status, atomic_read(&intf->pm_usage_cnt)); |
1559 | } | 1574 | } |
1560 | EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); | 1575 | EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); |
1561 | 1576 | ||
@@ -1599,7 +1614,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) | |||
1599 | 1614 | ||
1600 | status = usb_autopm_do_interface(intf, 1); | 1615 | status = usb_autopm_do_interface(intf, 1); |
1601 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", | 1616 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", |
1602 | __func__, status, intf->pm_usage_cnt); | 1617 | __func__, status, atomic_read(&intf->pm_usage_cnt)); |
1603 | return status; | 1618 | return status; |
1604 | } | 1619 | } |
1605 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface); | 1620 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface); |
@@ -1627,10 +1642,14 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) | |||
1627 | status = -ENODEV; | 1642 | status = -ENODEV; |
1628 | else if (udev->autoresume_disabled) | 1643 | else if (udev->autoresume_disabled) |
1629 | status = -EPERM; | 1644 | status = -EPERM; |
1630 | else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED) | 1645 | else { |
1631 | queue_work(ksuspend_usb_wq, &udev->autoresume); | 1646 | atomic_inc(&intf->pm_usage_cnt); |
1647 | if (atomic_read(&intf->pm_usage_cnt) > 0 && | ||
1648 | udev->state == USB_STATE_SUSPENDED) | ||
1649 | queue_work(ksuspend_usb_wq, &udev->autoresume); | ||
1650 | } | ||
1632 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", | 1651 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", |
1633 | __func__, status, intf->pm_usage_cnt); | 1652 | __func__, status, atomic_read(&intf->pm_usage_cnt)); |
1634 | return status; | 1653 | return status; |
1635 | } | 1654 | } |
1636 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); | 1655 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); |
@@ -1652,7 +1671,7 @@ int usb_autopm_set_interface(struct usb_interface *intf) | |||
1652 | 1671 | ||
1653 | status = usb_autopm_do_interface(intf, 0); | 1672 | status = usb_autopm_do_interface(intf, 0); |
1654 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", | 1673 | dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", |
1655 | __func__, status, intf->pm_usage_cnt); | 1674 | __func__, status, atomic_read(&intf->pm_usage_cnt)); |
1656 | return status; | 1675 | return status; |
1657 | } | 1676 | } |
1658 | EXPORT_SYMBOL_GPL(usb_autopm_set_interface); | 1677 | EXPORT_SYMBOL_GPL(usb_autopm_set_interface); |