aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-12-05 14:10:34 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-01-07 13:00:08 -0500
commit3b23dd6f8a718e5339de4f7d86ce76a078b5f771 (patch)
tree500a0402d7d8ba9afefc316124c1a6b4b4d575b2 /drivers/usb
parentb9cef6c31913c34fb1065b1d01e04c3b92c59016 (diff)
USB: utilize the bus notifiers
This patch (as1185) makes usbcore take advantage of the bus notifications sent out by the driver core. Now we can create all our device and interface attribute files before the device or interface uevent is broadcast. A side effect is that we no longer create the endpoint "pseudo" devices at the same time as a device or interface is registered -- it seems like a bad idea to try registering an endpoint before the registration of its parent is complete. So the routines for creating and removing endpoint devices have been split out and renamed, and they are called explicitly when needed. A new bitflag is used for keeping track of whether or not the interface's endpoint devices have been created, since (just as with the interface attributes) they vary with the altsetting and hence can be changed at random times. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-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
6 files changed, 91 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);