diff options
Diffstat (limited to 'drivers/usb/core/message.c')
-rw-r--r-- | drivers/usb/core/message.c | 164 |
1 files changed, 140 insertions, 24 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 6d1048faf08e..de51667dd64d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include "hcd.h" /* for usbcore internals */ | 18 | #include "hcd.h" /* for usbcore internals */ |
19 | #include "usb.h" | 19 | #include "usb.h" |
20 | 20 | ||
21 | static void cancel_async_set_config(struct usb_device *udev); | ||
22 | |||
21 | struct api_context { | 23 | struct api_context { |
22 | struct completion done; | 24 | struct completion done; |
23 | int status; | 25 | int status; |
@@ -139,9 +141,9 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, | |||
139 | 141 | ||
140 | dr->bRequestType = requesttype; | 142 | dr->bRequestType = requesttype; |
141 | dr->bRequest = request; | 143 | dr->bRequest = request; |
142 | dr->wValue = cpu_to_le16p(&value); | 144 | dr->wValue = cpu_to_le16(value); |
143 | dr->wIndex = cpu_to_le16p(&index); | 145 | dr->wIndex = cpu_to_le16(index); |
144 | dr->wLength = cpu_to_le16p(&size); | 146 | dr->wLength = cpu_to_le16(size); |
145 | 147 | ||
146 | /* dbg("usb_control_msg"); */ | 148 | /* dbg("usb_control_msg"); */ |
147 | 149 | ||
@@ -1004,6 +1006,34 @@ int usb_clear_halt(struct usb_device *dev, int pipe) | |||
1004 | } | 1006 | } |
1005 | EXPORT_SYMBOL_GPL(usb_clear_halt); | 1007 | EXPORT_SYMBOL_GPL(usb_clear_halt); |
1006 | 1008 | ||
1009 | static int create_intf_ep_devs(struct usb_interface *intf) | ||
1010 | { | ||
1011 | struct usb_device *udev = interface_to_usbdev(intf); | ||
1012 | struct usb_host_interface *alt = intf->cur_altsetting; | ||
1013 | int i; | ||
1014 | |||
1015 | if (intf->ep_devs_created || intf->unregistering) | ||
1016 | return 0; | ||
1017 | |||
1018 | for (i = 0; i < alt->desc.bNumEndpoints; ++i) | ||
1019 | (void) usb_create_ep_devs(&intf->dev, &alt->endpoint[i], udev); | ||
1020 | intf->ep_devs_created = 1; | ||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | static void remove_intf_ep_devs(struct usb_interface *intf) | ||
1025 | { | ||
1026 | struct usb_host_interface *alt = intf->cur_altsetting; | ||
1027 | int i; | ||
1028 | |||
1029 | if (!intf->ep_devs_created) | ||
1030 | return; | ||
1031 | |||
1032 | for (i = 0; i < alt->desc.bNumEndpoints; ++i) | ||
1033 | usb_remove_ep_devs(&alt->endpoint[i]); | ||
1034 | intf->ep_devs_created = 0; | ||
1035 | } | ||
1036 | |||
1007 | /** | 1037 | /** |
1008 | * usb_disable_endpoint -- Disable an endpoint by address | 1038 | * usb_disable_endpoint -- Disable an endpoint by address |
1009 | * @dev: the device whose endpoint is being disabled | 1039 | * @dev: the device whose endpoint is being disabled |
@@ -1092,7 +1122,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) | |||
1092 | dev_dbg(&dev->dev, "unregistering interface %s\n", | 1122 | dev_dbg(&dev->dev, "unregistering interface %s\n", |
1093 | dev_name(&interface->dev)); | 1123 | dev_name(&interface->dev)); |
1094 | interface->unregistering = 1; | 1124 | interface->unregistering = 1; |
1095 | usb_remove_sysfs_intf_files(interface); | 1125 | remove_intf_ep_devs(interface); |
1096 | device_del(&interface->dev); | 1126 | device_del(&interface->dev); |
1097 | } | 1127 | } |
1098 | 1128 | ||
@@ -1113,22 +1143,26 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) | |||
1113 | * usb_enable_endpoint - Enable an endpoint for USB communications | 1143 | * usb_enable_endpoint - Enable an endpoint for USB communications |
1114 | * @dev: the device whose interface is being enabled | 1144 | * @dev: the device whose interface is being enabled |
1115 | * @ep: the endpoint | 1145 | * @ep: the endpoint |
1146 | * @reset_toggle: flag to set the endpoint's toggle back to 0 | ||
1116 | * | 1147 | * |
1117 | * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers. | 1148 | * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers. |
1118 | * For control endpoints, both the input and output sides are handled. | 1149 | * For control endpoints, both the input and output sides are handled. |
1119 | */ | 1150 | */ |
1120 | void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) | 1151 | void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, |
1152 | bool reset_toggle) | ||
1121 | { | 1153 | { |
1122 | int epnum = usb_endpoint_num(&ep->desc); | 1154 | int epnum = usb_endpoint_num(&ep->desc); |
1123 | int is_out = usb_endpoint_dir_out(&ep->desc); | 1155 | int is_out = usb_endpoint_dir_out(&ep->desc); |
1124 | int is_control = usb_endpoint_xfer_control(&ep->desc); | 1156 | int is_control = usb_endpoint_xfer_control(&ep->desc); |
1125 | 1157 | ||
1126 | if (is_out || is_control) { | 1158 | if (is_out || is_control) { |
1127 | usb_settoggle(dev, epnum, 1, 0); | 1159 | if (reset_toggle) |
1160 | usb_settoggle(dev, epnum, 1, 0); | ||
1128 | dev->ep_out[epnum] = ep; | 1161 | dev->ep_out[epnum] = ep; |
1129 | } | 1162 | } |
1130 | if (!is_out || is_control) { | 1163 | if (!is_out || is_control) { |
1131 | usb_settoggle(dev, epnum, 0, 0); | 1164 | if (reset_toggle) |
1165 | usb_settoggle(dev, epnum, 0, 0); | ||
1132 | dev->ep_in[epnum] = ep; | 1166 | dev->ep_in[epnum] = ep; |
1133 | } | 1167 | } |
1134 | ep->enabled = 1; | 1168 | ep->enabled = 1; |
@@ -1138,17 +1172,18 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep) | |||
1138 | * usb_enable_interface - Enable all the endpoints for an interface | 1172 | * usb_enable_interface - Enable all the endpoints for an interface |
1139 | * @dev: the device whose interface is being enabled | 1173 | * @dev: the device whose interface is being enabled |
1140 | * @intf: pointer to the interface descriptor | 1174 | * @intf: pointer to the interface descriptor |
1175 | * @reset_toggles: flag to set the endpoints' toggles back to 0 | ||
1141 | * | 1176 | * |
1142 | * Enables all the endpoints for the interface's current altsetting. | 1177 | * Enables all the endpoints for the interface's current altsetting. |
1143 | */ | 1178 | */ |
1144 | static void usb_enable_interface(struct usb_device *dev, | 1179 | void usb_enable_interface(struct usb_device *dev, |
1145 | struct usb_interface *intf) | 1180 | struct usb_interface *intf, bool reset_toggles) |
1146 | { | 1181 | { |
1147 | struct usb_host_interface *alt = intf->cur_altsetting; | 1182 | struct usb_host_interface *alt = intf->cur_altsetting; |
1148 | int i; | 1183 | int i; |
1149 | 1184 | ||
1150 | for (i = 0; i < alt->desc.bNumEndpoints; ++i) | 1185 | for (i = 0; i < alt->desc.bNumEndpoints; ++i) |
1151 | usb_enable_endpoint(dev, &alt->endpoint[i]); | 1186 | usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles); |
1152 | } | 1187 | } |
1153 | 1188 | ||
1154 | /** | 1189 | /** |
@@ -1235,8 +1270,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) | |||
1235 | */ | 1270 | */ |
1236 | 1271 | ||
1237 | /* prevent submissions using previous endpoint settings */ | 1272 | /* prevent submissions using previous endpoint settings */ |
1238 | if (iface->cur_altsetting != alt) | 1273 | if (iface->cur_altsetting != alt) { |
1274 | remove_intf_ep_devs(iface); | ||
1239 | usb_remove_sysfs_intf_files(iface); | 1275 | usb_remove_sysfs_intf_files(iface); |
1276 | } | ||
1240 | usb_disable_interface(dev, iface); | 1277 | usb_disable_interface(dev, iface); |
1241 | 1278 | ||
1242 | iface->cur_altsetting = alt; | 1279 | iface->cur_altsetting = alt; |
@@ -1271,10 +1308,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) | |||
1271 | * during the SETUP stage - hence EP0 toggles are "don't care" here. | 1308 | * during the SETUP stage - hence EP0 toggles are "don't care" here. |
1272 | * (Likewise, EP0 never "halts" on well designed devices.) | 1309 | * (Likewise, EP0 never "halts" on well designed devices.) |
1273 | */ | 1310 | */ |
1274 | usb_enable_interface(dev, iface); | 1311 | usb_enable_interface(dev, iface, true); |
1275 | if (device_is_registered(&iface->dev)) | 1312 | if (device_is_registered(&iface->dev)) { |
1276 | usb_create_sysfs_intf_files(iface); | 1313 | usb_create_sysfs_intf_files(iface); |
1277 | 1314 | create_intf_ep_devs(iface); | |
1315 | } | ||
1278 | return 0; | 1316 | return 0; |
1279 | } | 1317 | } |
1280 | EXPORT_SYMBOL_GPL(usb_set_interface); | 1318 | EXPORT_SYMBOL_GPL(usb_set_interface); |
@@ -1334,7 +1372,6 @@ int usb_reset_configuration(struct usb_device *dev) | |||
1334 | struct usb_interface *intf = config->interface[i]; | 1372 | struct usb_interface *intf = config->interface[i]; |
1335 | struct usb_host_interface *alt; | 1373 | struct usb_host_interface *alt; |
1336 | 1374 | ||
1337 | usb_remove_sysfs_intf_files(intf); | ||
1338 | alt = usb_altnum_to_altsetting(intf, 0); | 1375 | alt = usb_altnum_to_altsetting(intf, 0); |
1339 | 1376 | ||
1340 | /* No altsetting 0? We'll assume the first altsetting. | 1377 | /* No altsetting 0? We'll assume the first altsetting. |
@@ -1345,10 +1382,16 @@ int usb_reset_configuration(struct usb_device *dev) | |||
1345 | if (!alt) | 1382 | if (!alt) |
1346 | alt = &intf->altsetting[0]; | 1383 | alt = &intf->altsetting[0]; |
1347 | 1384 | ||
1385 | if (alt != intf->cur_altsetting) { | ||
1386 | remove_intf_ep_devs(intf); | ||
1387 | usb_remove_sysfs_intf_files(intf); | ||
1388 | } | ||
1348 | intf->cur_altsetting = alt; | 1389 | intf->cur_altsetting = alt; |
1349 | usb_enable_interface(dev, intf); | 1390 | usb_enable_interface(dev, intf, true); |
1350 | if (device_is_registered(&intf->dev)) | 1391 | if (device_is_registered(&intf->dev)) { |
1351 | usb_create_sysfs_intf_files(intf); | 1392 | usb_create_sysfs_intf_files(intf); |
1393 | create_intf_ep_devs(intf); | ||
1394 | } | ||
1352 | } | 1395 | } |
1353 | return 0; | 1396 | return 0; |
1354 | } | 1397 | } |
@@ -1441,6 +1484,46 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, | |||
1441 | return retval; | 1484 | return retval; |
1442 | } | 1485 | } |
1443 | 1486 | ||
1487 | |||
1488 | /* | ||
1489 | * Internal function to queue a device reset | ||
1490 | * | ||
1491 | * This is initialized into the workstruct in 'struct | ||
1492 | * usb_device->reset_ws' that is launched by | ||
1493 | * message.c:usb_set_configuration() when initializing each 'struct | ||
1494 | * usb_interface'. | ||
1495 | * | ||
1496 | * It is safe to get the USB device without reference counts because | ||
1497 | * the life cycle of @iface is bound to the life cycle of @udev. Then, | ||
1498 | * this function will be ran only if @iface is alive (and before | ||
1499 | * freeing it any scheduled instances of it will have been cancelled). | ||
1500 | * | ||
1501 | * We need to set a flag (usb_dev->reset_running) because when we call | ||
1502 | * the reset, the interfaces might be unbound. The current interface | ||
1503 | * cannot try to remove the queued work as it would cause a deadlock | ||
1504 | * (you cannot remove your work from within your executing | ||
1505 | * workqueue). This flag lets it know, so that | ||
1506 | * usb_cancel_queued_reset() doesn't try to do it. | ||
1507 | * | ||
1508 | * See usb_queue_reset_device() for more details | ||
1509 | */ | ||
1510 | void __usb_queue_reset_device(struct work_struct *ws) | ||
1511 | { | ||
1512 | int rc; | ||
1513 | struct usb_interface *iface = | ||
1514 | container_of(ws, struct usb_interface, reset_ws); | ||
1515 | struct usb_device *udev = interface_to_usbdev(iface); | ||
1516 | |||
1517 | rc = usb_lock_device_for_reset(udev, iface); | ||
1518 | if (rc >= 0) { | ||
1519 | iface->reset_running = 1; | ||
1520 | usb_reset_device(udev); | ||
1521 | iface->reset_running = 0; | ||
1522 | usb_unlock_device(udev); | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | |||
1444 | /* | 1527 | /* |
1445 | * usb_set_configuration - Makes a particular device setting be current | 1528 | * usb_set_configuration - Makes a particular device setting be current |
1446 | * @dev: the device whose configuration is being updated | 1529 | * @dev: the device whose configuration is being updated |
@@ -1560,6 +1643,9 @@ free_interfaces: | |||
1560 | if (dev->state != USB_STATE_ADDRESS) | 1643 | if (dev->state != USB_STATE_ADDRESS) |
1561 | usb_disable_device(dev, 1); /* Skip ep0 */ | 1644 | usb_disable_device(dev, 1); /* Skip ep0 */ |
1562 | 1645 | ||
1646 | /* Get rid of pending async Set-Config requests for this device */ | ||
1647 | cancel_async_set_config(dev); | ||
1648 | |||
1563 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1649 | ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
1564 | USB_REQ_SET_CONFIGURATION, 0, configuration, 0, | 1650 | USB_REQ_SET_CONFIGURATION, 0, configuration, 0, |
1565 | NULL, 0, USB_CTRL_SET_TIMEOUT); | 1651 | NULL, 0, USB_CTRL_SET_TIMEOUT); |
@@ -1604,13 +1690,14 @@ free_interfaces: | |||
1604 | alt = &intf->altsetting[0]; | 1690 | alt = &intf->altsetting[0]; |
1605 | 1691 | ||
1606 | intf->cur_altsetting = alt; | 1692 | intf->cur_altsetting = alt; |
1607 | usb_enable_interface(dev, intf); | 1693 | usb_enable_interface(dev, intf, true); |
1608 | intf->dev.parent = &dev->dev; | 1694 | intf->dev.parent = &dev->dev; |
1609 | intf->dev.driver = NULL; | 1695 | intf->dev.driver = NULL; |
1610 | intf->dev.bus = &usb_bus_type; | 1696 | intf->dev.bus = &usb_bus_type; |
1611 | intf->dev.type = &usb_if_device_type; | 1697 | intf->dev.type = &usb_if_device_type; |
1612 | intf->dev.groups = usb_interface_groups; | 1698 | intf->dev.groups = usb_interface_groups; |
1613 | intf->dev.dma_mask = dev->dev.dma_mask; | 1699 | intf->dev.dma_mask = dev->dev.dma_mask; |
1700 | INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); | ||
1614 | device_initialize(&intf->dev); | 1701 | device_initialize(&intf->dev); |
1615 | mark_quiesced(intf); | 1702 | mark_quiesced(intf); |
1616 | dev_set_name(&intf->dev, "%d-%s:%d.%d", | 1703 | dev_set_name(&intf->dev, "%d-%s:%d.%d", |
@@ -1641,17 +1728,21 @@ free_interfaces: | |||
1641 | dev_name(&intf->dev), ret); | 1728 | dev_name(&intf->dev), ret); |
1642 | continue; | 1729 | continue; |
1643 | } | 1730 | } |
1644 | usb_create_sysfs_intf_files(intf); | 1731 | create_intf_ep_devs(intf); |
1645 | } | 1732 | } |
1646 | 1733 | ||
1647 | usb_autosuspend_device(dev); | 1734 | usb_autosuspend_device(dev); |
1648 | return 0; | 1735 | return 0; |
1649 | } | 1736 | } |
1650 | 1737 | ||
1738 | static LIST_HEAD(set_config_list); | ||
1739 | static DEFINE_SPINLOCK(set_config_lock); | ||
1740 | |||
1651 | struct set_config_request { | 1741 | struct set_config_request { |
1652 | struct usb_device *udev; | 1742 | struct usb_device *udev; |
1653 | int config; | 1743 | int config; |
1654 | struct work_struct work; | 1744 | struct work_struct work; |
1745 | struct list_head node; | ||
1655 | }; | 1746 | }; |
1656 | 1747 | ||
1657 | /* Worker routine for usb_driver_set_configuration() */ | 1748 | /* Worker routine for usb_driver_set_configuration() */ |
@@ -1659,14 +1750,35 @@ static void driver_set_config_work(struct work_struct *work) | |||
1659 | { | 1750 | { |
1660 | struct set_config_request *req = | 1751 | struct set_config_request *req = |
1661 | container_of(work, struct set_config_request, work); | 1752 | container_of(work, struct set_config_request, work); |
1753 | struct usb_device *udev = req->udev; | ||
1754 | |||
1755 | usb_lock_device(udev); | ||
1756 | spin_lock(&set_config_lock); | ||
1757 | list_del(&req->node); | ||
1758 | spin_unlock(&set_config_lock); | ||
1662 | 1759 | ||
1663 | usb_lock_device(req->udev); | 1760 | if (req->config >= -1) /* Is req still valid? */ |
1664 | usb_set_configuration(req->udev, req->config); | 1761 | usb_set_configuration(udev, req->config); |
1665 | usb_unlock_device(req->udev); | 1762 | usb_unlock_device(udev); |
1666 | usb_put_dev(req->udev); | 1763 | usb_put_dev(udev); |
1667 | kfree(req); | 1764 | kfree(req); |
1668 | } | 1765 | } |
1669 | 1766 | ||
1767 | /* Cancel pending Set-Config requests for a device whose configuration | ||
1768 | * was just changed | ||
1769 | */ | ||
1770 | static void cancel_async_set_config(struct usb_device *udev) | ||
1771 | { | ||
1772 | struct set_config_request *req; | ||
1773 | |||
1774 | spin_lock(&set_config_lock); | ||
1775 | list_for_each_entry(req, &set_config_list, node) { | ||
1776 | if (req->udev == udev) | ||
1777 | req->config = -999; /* Mark as cancelled */ | ||
1778 | } | ||
1779 | spin_unlock(&set_config_lock); | ||
1780 | } | ||
1781 | |||
1670 | /** | 1782 | /** |
1671 | * usb_driver_set_configuration - Provide a way for drivers to change device configurations | 1783 | * usb_driver_set_configuration - Provide a way for drivers to change device configurations |
1672 | * @udev: the device whose configuration is being updated | 1784 | * @udev: the device whose configuration is being updated |
@@ -1698,6 +1810,10 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) | |||
1698 | req->config = config; | 1810 | req->config = config; |
1699 | INIT_WORK(&req->work, driver_set_config_work); | 1811 | INIT_WORK(&req->work, driver_set_config_work); |
1700 | 1812 | ||
1813 | spin_lock(&set_config_lock); | ||
1814 | list_add(&req->node, &set_config_list); | ||
1815 | spin_unlock(&set_config_lock); | ||
1816 | |||
1701 | usb_get_dev(udev); | 1817 | usb_get_dev(udev); |
1702 | schedule_work(&req->work); | 1818 | schedule_work(&req->work); |
1703 | return 0; | 1819 | return 0; |