aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/message.c')
-rw-r--r--drivers/usb/core/message.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 5701e857392b..0b5ec234c787 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1135,15 +1135,26 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
1135 * Deallocates hcd/hardware state for the endpoints (nuking all or most 1135 * Deallocates hcd/hardware state for the endpoints (nuking all or most
1136 * pending urbs) and usbcore state for the interfaces, so that usbcore 1136 * pending urbs) and usbcore state for the interfaces, so that usbcore
1137 * must usb_set_configuration() before any interfaces could be used. 1137 * must usb_set_configuration() before any interfaces could be used.
1138 *
1139 * Must be called with hcd->bandwidth_mutex held.
1138 */ 1140 */
1139void usb_disable_device(struct usb_device *dev, int skip_ep0) 1141void usb_disable_device(struct usb_device *dev, int skip_ep0)
1140{ 1142{
1141 int i; 1143 int i;
1144 struct usb_hcd *hcd = bus_to_hcd(dev->bus);
1142 1145
1143 /* getting rid of interfaces will disconnect 1146 /* getting rid of interfaces will disconnect
1144 * any drivers bound to them (a key side effect) 1147 * any drivers bound to them (a key side effect)
1145 */ 1148 */
1146 if (dev->actconfig) { 1149 if (dev->actconfig) {
1150 /*
1151 * FIXME: In order to avoid self-deadlock involving the
1152 * bandwidth_mutex, we have to mark all the interfaces
1153 * before unregistering any of them.
1154 */
1155 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
1156 dev->actconfig->interface[i]->unregistering = 1;
1157
1147 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { 1158 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
1148 struct usb_interface *interface; 1159 struct usb_interface *interface;
1149 1160
@@ -1153,7 +1164,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
1153 continue; 1164 continue;
1154 dev_dbg(&dev->dev, "unregistering interface %s\n", 1165 dev_dbg(&dev->dev, "unregistering interface %s\n",
1155 dev_name(&interface->dev)); 1166 dev_name(&interface->dev));
1156 interface->unregistering = 1;
1157 remove_intf_ep_devs(interface); 1167 remove_intf_ep_devs(interface);
1158 device_del(&interface->dev); 1168 device_del(&interface->dev);
1159 } 1169 }
@@ -1172,6 +1182,16 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
1172 1182
1173 dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__, 1183 dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
1174 skip_ep0 ? "non-ep0" : "all"); 1184 skip_ep0 ? "non-ep0" : "all");
1185 if (hcd->driver->check_bandwidth) {
1186 /* First pass: Cancel URBs, leave endpoint pointers intact. */
1187 for (i = skip_ep0; i < 16; ++i) {
1188 usb_disable_endpoint(dev, i, false);
1189 usb_disable_endpoint(dev, i + USB_DIR_IN, false);
1190 }
1191 /* Remove endpoints from the host controller internal state */
1192 usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
1193 /* Second pass: remove endpoint pointers */
1194 }
1175 for (i = skip_ep0; i < 16; ++i) { 1195 for (i = skip_ep0; i < 16; ++i) {
1176 usb_disable_endpoint(dev, i, true); 1196 usb_disable_endpoint(dev, i, true);
1177 usb_disable_endpoint(dev, i + USB_DIR_IN, true); 1197 usb_disable_endpoint(dev, i + USB_DIR_IN, true);
@@ -1273,6 +1293,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1273 interface); 1293 interface);
1274 return -EINVAL; 1294 return -EINVAL;
1275 } 1295 }
1296 if (iface->unregistering)
1297 return -ENODEV;
1276 1298
1277 alt = usb_altnum_to_altsetting(iface, alternate); 1299 alt = usb_altnum_to_altsetting(iface, alternate);
1278 if (!alt) { 1300 if (!alt) {
@@ -1727,6 +1749,7 @@ free_interfaces:
1727 /* if it's already configured, clear out old state first. 1749 /* if it's already configured, clear out old state first.
1728 * getting rid of old interfaces means unbinding their drivers. 1750 * getting rid of old interfaces means unbinding their drivers.
1729 */ 1751 */
1752 mutex_lock(hcd->bandwidth_mutex);
1730 if (dev->state != USB_STATE_ADDRESS) 1753 if (dev->state != USB_STATE_ADDRESS)
1731 usb_disable_device(dev, 1); /* Skip ep0 */ 1754 usb_disable_device(dev, 1); /* Skip ep0 */
1732 1755
@@ -1739,7 +1762,6 @@ free_interfaces:
1739 * host controller will not allow submissions to dropped endpoints. If 1762 * host controller will not allow submissions to dropped endpoints. If
1740 * this call fails, the device state is unchanged. 1763 * this call fails, the device state is unchanged.
1741 */ 1764 */
1742 mutex_lock(hcd->bandwidth_mutex);
1743 ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); 1765 ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
1744 if (ret < 0) { 1766 if (ret < 0) {
1745 mutex_unlock(hcd->bandwidth_mutex); 1767 mutex_unlock(hcd->bandwidth_mutex);