Greg, here's one for the next merge window. It fixes an obscure logic bug that strikes only few drivers in an unlikely error case. Regards Oliver Signed-off-by: Oliver Neukum <oliver@xxxxxxxxxx> -- commit 092d62009be992df7d6ba6c7c6acb91ca58567b5 Author: Oliver Neukum <oliver@xxxxxxxxxx> Date: Wed Nov 25 10:22:20 2009 +0100 usb:fix unbalanced calls to post_reset() in usb_reset_device() usb_reset_device() can mean drivers are disconnected or reconnected for such drivers post_reset() must not be called. Therefore do the post_reset() and the probing in two passes diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5ce8391..b326ccc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3652,16 +3652,17 @@ int usb_reset_device(struct usb_device *udev) int i; struct usb_host_config *config = udev->actconfig; - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) { + /* Prevent autosuspend during the reset */ + ret = usb_autoresume_device(udev); + if (ret < 0) + return ret; + + if (udev->state == USB_STATE_NOTATTACHED) { dev_dbg(&udev->dev, "device reset not allowed in state %d\n", udev->state); return -EINVAL; } - /* Prevent autosuspend during the reset */ - usb_autoresume_device(udev); - if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { struct usb_interface *cintf = config->interface[i]; @@ -3687,17 +3688,23 @@ 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 (!rebind && cintf->dev.driver) { + if (!cintf->needs_binding && cintf->dev.driver) { drv = to_usb_driver(cintf->dev.driver); - if (drv->post_reset) - rebind = (drv->post_reset)(cintf); - else if (cintf->condition == - USB_INTERFACE_BOUND) - rebind = 1; + cintf->needs_binding = (drv->post_reset)(cintf) + ? 1 : 0; } - if (ret == 0 && rebind) + } + + /* + * Don't rebind until after all the post_reset() calls + * so that a newly bound driver does not get an unbalanced + * call to post_reset() + */ + for (i = config->desc.bNumInterfaces - 1; i >= 0; --i){ + struct usb_interface *cintf = config->interface[i]; + + if (ret == 0 && cintf->needs_binding) usb_rebind_intf(cintf); } } -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html