aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/endpoint.c4
-rw-r--r--drivers/usb/core/hub.c18
-rw-r--r--drivers/usb/core/message.c50
-rw-r--r--drivers/usb/core/sysfs.c22
-rw-r--r--drivers/usb/core/usb.c37
-rw-r--r--drivers/usb/core/usb.h4
-rw-r--r--include/linux/usb.h2
7 files changed, 93 insertions, 44 deletions
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 946fae43d622..e1710f260b4f 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -276,7 +276,7 @@ static void ep_device_release(struct device *dev)
276 kfree(ep_dev); 276 kfree(ep_dev);
277} 277}
278 278
279int usb_create_ep_files(struct device *parent, 279int usb_create_ep_devs(struct device *parent,
280 struct usb_host_endpoint *endpoint, 280 struct usb_host_endpoint *endpoint,
281 struct usb_device *udev) 281 struct usb_device *udev)
282{ 282{
@@ -340,7 +340,7 @@ exit:
340 return retval; 340 return retval;
341} 341}
342 342
343void usb_remove_ep_files(struct usb_host_endpoint *endpoint) 343void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
344{ 344{
345 struct ep_device *ep_dev = endpoint->ep_dev; 345 struct ep_device *ep_dev = endpoint->ep_dev;
346 346
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5abdc11be1e5..756b8d9993fc 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1437,17 +1437,12 @@ void usb_disconnect(struct usb_device **pdev)
1437 usb_disable_device(udev, 0); 1437 usb_disable_device(udev, 0);
1438 usb_hcd_synchronize_unlinks(udev); 1438 usb_hcd_synchronize_unlinks(udev);
1439 1439
1440 usb_remove_ep_devs(&udev->ep0);
1440 usb_unlock_device(udev); 1441 usb_unlock_device(udev);
1441 1442
1442 /* Remove the device-specific files from sysfs. This must be
1443 * done with udev unlocked, because some of the attribute
1444 * routines try to acquire the device lock.
1445 */
1446 usb_remove_sysfs_dev_files(udev);
1447
1448 /* Unregister the device. The device driver is responsible 1443 /* Unregister the device. The device driver is responsible
1449 * for removing the device files from usbfs and sysfs and for 1444 * for de-configuring the device and invoking the remove-device
1450 * de-configuring the device. 1445 * notifier chain (used by usbfs and possibly others).
1451 */ 1446 */
1452 device_del(&udev->dev); 1447 device_del(&udev->dev);
1453 1448
@@ -1654,8 +1649,8 @@ int usb_new_device(struct usb_device *udev)
1654 announce_device(udev); 1649 announce_device(udev);
1655 1650
1656 /* Register the device. The device driver is responsible 1651 /* Register the device. The device driver is responsible
1657 * for adding the device files to sysfs and for configuring 1652 * for configuring the device and invoking the add-device
1658 * the device. 1653 * notifier chain (used by usbfs and possibly others).
1659 */ 1654 */
1660 err = device_add(&udev->dev); 1655 err = device_add(&udev->dev);
1661 if (err) { 1656 if (err) {
@@ -1663,8 +1658,7 @@ int usb_new_device(struct usb_device *udev)
1663 goto fail; 1658 goto fail;
1664 } 1659 }
1665 1660
1666 /* put device-specific files into sysfs */ 1661 (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
1667 usb_create_sysfs_dev_files(udev);
1668 return err; 1662 return err;
1669 1663
1670fail: 1664fail:
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index aadf29f09c45..7943901c641c 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1004,6 +1004,34 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
1004} 1004}
1005EXPORT_SYMBOL_GPL(usb_clear_halt); 1005EXPORT_SYMBOL_GPL(usb_clear_halt);
1006 1006
1007static int create_intf_ep_devs(struct usb_interface *intf)
1008{
1009 struct usb_device *udev = interface_to_usbdev(intf);
1010 struct usb_host_interface *alt = intf->cur_altsetting;
1011 int i;
1012
1013 if (intf->ep_devs_created || intf->unregistering)
1014 return 0;
1015
1016 for (i = 0; i < alt->desc.bNumEndpoints; ++i)
1017 (void) usb_create_ep_devs(&intf->dev, &alt->endpoint[i], udev);
1018 intf->ep_devs_created = 1;
1019 return 0;
1020}
1021
1022static void remove_intf_ep_devs(struct usb_interface *intf)
1023{
1024 struct usb_host_interface *alt = intf->cur_altsetting;
1025 int i;
1026
1027 if (!intf->ep_devs_created)
1028 return;
1029
1030 for (i = 0; i < alt->desc.bNumEndpoints; ++i)
1031 usb_remove_ep_devs(&alt->endpoint[i]);
1032 intf->ep_devs_created = 0;
1033}
1034
1007/** 1035/**
1008 * usb_disable_endpoint -- Disable an endpoint by address 1036 * usb_disable_endpoint -- Disable an endpoint by address
1009 * @dev: the device whose endpoint is being disabled 1037 * @dev: the device whose endpoint is being disabled
@@ -1092,7 +1120,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
1092 dev_dbg(&dev->dev, "unregistering interface %s\n", 1120 dev_dbg(&dev->dev, "unregistering interface %s\n",
1093 dev_name(&interface->dev)); 1121 dev_name(&interface->dev));
1094 interface->unregistering = 1; 1122 interface->unregistering = 1;
1095 usb_remove_sysfs_intf_files(interface); 1123 remove_intf_ep_devs(interface);
1096 device_del(&interface->dev); 1124 device_del(&interface->dev);
1097 } 1125 }
1098 1126
@@ -1235,8 +1263,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1235 */ 1263 */
1236 1264
1237 /* prevent submissions using previous endpoint settings */ 1265 /* prevent submissions using previous endpoint settings */
1238 if (iface->cur_altsetting != alt) 1266 if (iface->cur_altsetting != alt) {
1267 remove_intf_ep_devs(iface);
1239 usb_remove_sysfs_intf_files(iface); 1268 usb_remove_sysfs_intf_files(iface);
1269 }
1240 usb_disable_interface(dev, iface); 1270 usb_disable_interface(dev, iface);
1241 1271
1242 iface->cur_altsetting = alt; 1272 iface->cur_altsetting = alt;
@@ -1272,9 +1302,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
1272 * (Likewise, EP0 never "halts" on well designed devices.) 1302 * (Likewise, EP0 never "halts" on well designed devices.)
1273 */ 1303 */
1274 usb_enable_interface(dev, iface); 1304 usb_enable_interface(dev, iface);
1275 if (device_is_registered(&iface->dev)) 1305 if (device_is_registered(&iface->dev)) {
1276 usb_create_sysfs_intf_files(iface); 1306 usb_create_sysfs_intf_files(iface);
1277 1307 create_intf_ep_devs(iface);
1308 }
1278 return 0; 1309 return 0;
1279} 1310}
1280EXPORT_SYMBOL_GPL(usb_set_interface); 1311EXPORT_SYMBOL_GPL(usb_set_interface);
@@ -1334,7 +1365,6 @@ int usb_reset_configuration(struct usb_device *dev)
1334 struct usb_interface *intf = config->interface[i]; 1365 struct usb_interface *intf = config->interface[i];
1335 struct usb_host_interface *alt; 1366 struct usb_host_interface *alt;
1336 1367
1337 usb_remove_sysfs_intf_files(intf);
1338 alt = usb_altnum_to_altsetting(intf, 0); 1368 alt = usb_altnum_to_altsetting(intf, 0);
1339 1369
1340 /* No altsetting 0? We'll assume the first altsetting. 1370 /* No altsetting 0? We'll assume the first altsetting.
@@ -1345,10 +1375,16 @@ int usb_reset_configuration(struct usb_device *dev)
1345 if (!alt) 1375 if (!alt)
1346 alt = &intf->altsetting[0]; 1376 alt = &intf->altsetting[0];
1347 1377
1378 if (alt != intf->cur_altsetting) {
1379 remove_intf_ep_devs(intf);
1380 usb_remove_sysfs_intf_files(intf);
1381 }
1348 intf->cur_altsetting = alt; 1382 intf->cur_altsetting = alt;
1349 usb_enable_interface(dev, intf); 1383 usb_enable_interface(dev, intf);
1350 if (device_is_registered(&intf->dev)) 1384 if (device_is_registered(&intf->dev)) {
1351 usb_create_sysfs_intf_files(intf); 1385 usb_create_sysfs_intf_files(intf);
1386 create_intf_ep_devs(intf);
1387 }
1352 } 1388 }
1353 return 0; 1389 return 0;
1354} 1390}
@@ -1682,7 +1718,7 @@ free_interfaces:
1682 dev_name(&intf->dev), ret); 1718 dev_name(&intf->dev), ret);
1683 continue; 1719 continue;
1684 } 1720 }
1685 usb_create_sysfs_intf_files(intf); 1721 create_intf_ep_devs(intf);
1686 } 1722 }
1687 1723
1688 usb_autosuspend_device(dev); 1724 usb_autosuspend_device(dev);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 0f0ccf640114..4cc2456ef3be 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -629,9 +629,6 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
629 struct device *dev = &udev->dev; 629 struct device *dev = &udev->dev;
630 int retval; 630 int retval;
631 631
632 /* Unforunately these attributes cannot be created before
633 * the uevent is broadcast.
634 */
635 retval = device_create_bin_file(dev, &dev_bin_attr_descriptors); 632 retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
636 if (retval) 633 if (retval)
637 goto error; 634 goto error;
@@ -643,11 +640,7 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
643 retval = add_power_attributes(dev); 640 retval = add_power_attributes(dev);
644 if (retval) 641 if (retval)
645 goto error; 642 goto error;
646 643 return retval;
647 retval = usb_create_ep_files(dev, &udev->ep0, udev);
648 if (retval)
649 goto error;
650 return 0;
651error: 644error:
652 usb_remove_sysfs_dev_files(udev); 645 usb_remove_sysfs_dev_files(udev);
653 return retval; 646 return retval;
@@ -657,7 +650,6 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
657{ 650{
658 struct device *dev = &udev->dev; 651 struct device *dev = &udev->dev;
659 652
660 usb_remove_ep_files(&udev->ep0);
661 remove_power_attributes(dev); 653 remove_power_attributes(dev);
662 remove_persist_attributes(dev); 654 remove_persist_attributes(dev);
663 device_remove_bin_file(dev, &dev_bin_attr_descriptors); 655 device_remove_bin_file(dev, &dev_bin_attr_descriptors);
@@ -816,36 +808,24 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
816{ 808{
817 struct usb_device *udev = interface_to_usbdev(intf); 809 struct usb_device *udev = interface_to_usbdev(intf);
818 struct usb_host_interface *alt = intf->cur_altsetting; 810 struct usb_host_interface *alt = intf->cur_altsetting;
819 int i;
820 int retval; 811 int retval;
821 812
822 if (intf->sysfs_files_created || intf->unregistering) 813 if (intf->sysfs_files_created || intf->unregistering)
823 return 0; 814 return 0;
824 815
825 /* The interface string may be present in some altsettings
826 * and missing in others. Hence its attribute cannot be created
827 * before the uevent is broadcast.
828 */
829 if (alt->string == NULL) 816 if (alt->string == NULL)
830 alt->string = usb_cache_string(udev, alt->desc.iInterface); 817 alt->string = usb_cache_string(udev, alt->desc.iInterface);
831 if (alt->string) 818 if (alt->string)
832 retval = device_create_file(&intf->dev, &dev_attr_interface); 819 retval = device_create_file(&intf->dev, &dev_attr_interface);
833 for (i = 0; i < alt->desc.bNumEndpoints; ++i)
834 usb_create_ep_files(&intf->dev, &alt->endpoint[i], udev);
835 intf->sysfs_files_created = 1; 820 intf->sysfs_files_created = 1;
836 return 0; 821 return 0;
837} 822}
838 823
839void usb_remove_sysfs_intf_files(struct usb_interface *intf) 824void usb_remove_sysfs_intf_files(struct usb_interface *intf)
840{ 825{
841 struct usb_host_interface *alt = intf->cur_altsetting;
842 int i;
843
844 if (!intf->sysfs_files_created) 826 if (!intf->sysfs_files_created)
845 return; 827 return;
846 828
847 for (i = 0; i < alt->desc.bNumEndpoints; ++i)
848 usb_remove_ep_files(&alt->endpoint[i]);
849 device_remove_file(&intf->dev, &dev_attr_interface); 829 device_remove_file(&intf->dev, &dev_attr_interface);
850 intf->sysfs_files_created = 0; 830 intf->sysfs_files_created = 0;
851} 831}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4c98f3975afe..c0821564a3fe 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -971,6 +971,37 @@ int usb_disabled(void)
971EXPORT_SYMBOL_GPL(usb_disabled); 971EXPORT_SYMBOL_GPL(usb_disabled);
972 972
973/* 973/*
974 * Notifications of device and interface registration
975 */
976static int usb_bus_notify(struct notifier_block *nb, unsigned long action,
977 void *data)
978{
979 struct device *dev = data;
980
981 switch (action) {
982 case BUS_NOTIFY_ADD_DEVICE:
983 if (dev->type == &usb_device_type)
984 (void) usb_create_sysfs_dev_files(to_usb_device(dev));
985 else if (dev->type == &usb_if_device_type)
986 (void) usb_create_sysfs_intf_files(
987 to_usb_interface(dev));
988 break;
989
990 case BUS_NOTIFY_DEL_DEVICE:
991 if (dev->type == &usb_device_type)
992 usb_remove_sysfs_dev_files(to_usb_device(dev));
993 else if (dev->type == &usb_if_device_type)
994 usb_remove_sysfs_intf_files(to_usb_interface(dev));
995 break;
996 }
997 return 0;
998}
999
1000static struct notifier_block usb_bus_nb = {
1001 .notifier_call = usb_bus_notify,
1002};
1003
1004/*
974 * Init 1005 * Init
975 */ 1006 */
976static int __init usb_init(void) 1007static int __init usb_init(void)
@@ -987,6 +1018,9 @@ static int __init usb_init(void)
987 retval = bus_register(&usb_bus_type); 1018 retval = bus_register(&usb_bus_type);
988 if (retval) 1019 if (retval)
989 goto bus_register_failed; 1020 goto bus_register_failed;
1021 retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
1022 if (retval)
1023 goto bus_notifier_failed;
990 retval = usb_host_init(); 1024 retval = usb_host_init();
991 if (retval) 1025 if (retval)
992 goto host_init_failed; 1026 goto host_init_failed;
@@ -1021,6 +1055,8 @@ driver_register_failed:
1021major_init_failed: 1055major_init_failed:
1022 usb_host_cleanup(); 1056 usb_host_cleanup();
1023host_init_failed: 1057host_init_failed:
1058 bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
1059bus_notifier_failed:
1024 bus_unregister(&usb_bus_type); 1060 bus_unregister(&usb_bus_type);
1025bus_register_failed: 1061bus_register_failed:
1026 ksuspend_usb_cleanup(); 1062 ksuspend_usb_cleanup();
@@ -1044,6 +1080,7 @@ static void __exit usb_exit(void)
1044 usb_devio_cleanup(); 1080 usb_devio_cleanup();
1045 usb_hub_cleanup(); 1081 usb_hub_cleanup();
1046 usb_host_cleanup(); 1082 usb_host_cleanup();
1083 bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
1047 bus_unregister(&usb_bus_type); 1084 bus_unregister(&usb_bus_type);
1048 ksuspend_usb_cleanup(); 1085 ksuspend_usb_cleanup();
1049} 1086}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 9fb195665fa8..381eae90c3b7 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -6,10 +6,10 @@ extern int usb_create_sysfs_dev_files(struct usb_device *dev);
6extern void usb_remove_sysfs_dev_files(struct usb_device *dev); 6extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
7extern int usb_create_sysfs_intf_files(struct usb_interface *intf); 7extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
8extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); 8extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
9extern int usb_create_ep_files(struct device *parent, 9extern int usb_create_ep_devs(struct device *parent,
10 struct usb_host_endpoint *endpoint, 10 struct usb_host_endpoint *endpoint,
11 struct usb_device *udev); 11 struct usb_device *udev);
12extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); 12extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint);
13 13
14extern void usb_enable_endpoint(struct usb_device *dev, 14extern void usb_enable_endpoint(struct usb_device *dev,
15 struct usb_host_endpoint *ep); 15 struct usb_host_endpoint *ep);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 74d0b9990c73..e9d63562325a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -108,6 +108,7 @@ enum usb_interface_condition {
108 * (in probe()), bound to a driver, or unbinding (in disconnect()) 108 * (in probe()), bound to a driver, or unbinding (in disconnect())
109 * @is_active: flag set when the interface is bound and not suspended. 109 * @is_active: flag set when the interface is bound and not suspended.
110 * @sysfs_files_created: sysfs attributes exist 110 * @sysfs_files_created: sysfs attributes exist
111 * @ep_devs_created: endpoint child pseudo-devices exist
111 * @unregistering: flag set when the interface is being unregistered 112 * @unregistering: flag set when the interface is being unregistered
112 * @needs_remote_wakeup: flag set when the driver requires remote-wakeup 113 * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
113 * capability during autosuspend. 114 * capability during autosuspend.
@@ -169,6 +170,7 @@ struct usb_interface {
169 enum usb_interface_condition condition; /* state of binding */ 170 enum usb_interface_condition condition; /* state of binding */
170 unsigned is_active:1; /* the interface is not suspended */ 171 unsigned is_active:1; /* the interface is not suspended */
171 unsigned sysfs_files_created:1; /* the sysfs attributes exist */ 172 unsigned sysfs_files_created:1; /* the sysfs attributes exist */
173 unsigned ep_devs_created:1; /* endpoint "devices" exist */
172 unsigned unregistering:1; /* unregistration is in progress */ 174 unsigned unregistering:1; /* unregistration is in progress */
173 unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ 175 unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
174 unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */ 176 unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */