Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
3b23dd6f b9cef6c3

+93 -44
+2 -2
drivers/usb/core/endpoint.c
··· 276 276 kfree(ep_dev); 277 277 } 278 278 279 - int usb_create_ep_files(struct device *parent, 279 + int usb_create_ep_devs(struct device *parent, 280 280 struct usb_host_endpoint *endpoint, 281 281 struct usb_device *udev) 282 282 { ··· 340 340 return retval; 341 341 } 342 342 343 - void usb_remove_ep_files(struct usb_host_endpoint *endpoint) 343 + void usb_remove_ep_devs(struct usb_host_endpoint *endpoint) 344 344 { 345 345 struct ep_device *ep_dev = endpoint->ep_dev; 346 346
+6 -12
drivers/usb/core/hub.c
··· 1437 1437 usb_disable_device(udev, 0); 1438 1438 usb_hcd_synchronize_unlinks(udev); 1439 1439 1440 + usb_remove_ep_devs(&udev->ep0); 1440 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 1443 /* Unregister the device. The device driver is responsible 1449 - * for removing the device files from usbfs and sysfs and for 1450 - * de-configuring the device. 1444 + * for de-configuring the device and invoking the remove-device 1445 + * notifier chain (used by usbfs and possibly others). 1451 1446 */ 1452 1447 device_del(&udev->dev); 1453 1448 ··· 1649 1654 announce_device(udev); 1650 1655 1651 1656 /* Register the device. The device driver is responsible 1652 - * for adding the device files to sysfs and for configuring 1653 - * the device. 1657 + * for configuring the device and invoking the add-device 1658 + * notifier chain (used by usbfs and possibly others). 1654 1659 */ 1655 1660 err = device_add(&udev->dev); 1656 1661 if (err) { ··· 1658 1663 goto fail; 1659 1664 } 1660 1665 1661 - /* put device-specific files into sysfs */ 1662 - usb_create_sysfs_dev_files(udev); 1666 + (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); 1663 1667 return err; 1664 1668 1665 1669 fail:
+43 -7
drivers/usb/core/message.c
··· 1004 1004 } 1005 1005 EXPORT_SYMBOL_GPL(usb_clear_halt); 1006 1006 1007 + static 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 + 1022 + static 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 1036 * usb_disable_endpoint -- Disable an endpoint by address 1009 1037 * @dev: the device whose endpoint is being disabled ··· 1120 1092 dev_dbg(&dev->dev, "unregistering interface %s\n", 1121 1093 dev_name(&interface->dev)); 1122 1094 interface->unregistering = 1; 1123 - usb_remove_sysfs_intf_files(interface); 1095 + remove_intf_ep_devs(interface); 1124 1096 device_del(&interface->dev); 1125 1097 } 1126 1098 ··· 1263 1235 */ 1264 1236 1265 1237 /* prevent submissions using previous endpoint settings */ 1266 - if (iface->cur_altsetting != alt) 1238 + if (iface->cur_altsetting != alt) { 1239 + remove_intf_ep_devs(iface); 1267 1240 usb_remove_sysfs_intf_files(iface); 1241 + } 1268 1242 usb_disable_interface(dev, iface); 1269 1243 1270 1244 iface->cur_altsetting = alt; ··· 1302 1272 * (Likewise, EP0 never "halts" on well designed devices.) 1303 1273 */ 1304 1274 usb_enable_interface(dev, iface); 1305 - if (device_is_registered(&iface->dev)) 1275 + if (device_is_registered(&iface->dev)) { 1306 1276 usb_create_sysfs_intf_files(iface); 1307 - 1277 + create_intf_ep_devs(iface); 1278 + } 1308 1279 return 0; 1309 1280 } 1310 1281 EXPORT_SYMBOL_GPL(usb_set_interface); ··· 1365 1334 struct usb_interface *intf = config->interface[i]; 1366 1335 struct usb_host_interface *alt; 1367 1336 1368 - usb_remove_sysfs_intf_files(intf); 1369 1337 alt = usb_altnum_to_altsetting(intf, 0); 1370 1338 1371 1339 /* No altsetting 0? We'll assume the first altsetting. ··· 1375 1345 if (!alt) 1376 1346 alt = &intf->altsetting[0]; 1377 1347 1348 + if (alt != intf->cur_altsetting) { 1349 + remove_intf_ep_devs(intf); 1350 + usb_remove_sysfs_intf_files(intf); 1351 + } 1378 1352 intf->cur_altsetting = alt; 1379 1353 usb_enable_interface(dev, intf); 1380 - if (device_is_registered(&intf->dev)) 1354 + if (device_is_registered(&intf->dev)) { 1381 1355 usb_create_sysfs_intf_files(intf); 1356 + create_intf_ep_devs(intf); 1357 + } 1382 1358 } 1383 1359 return 0; 1384 1360 } ··· 1718 1682 dev_name(&intf->dev), ret); 1719 1683 continue; 1720 1684 } 1721 - usb_create_sysfs_intf_files(intf); 1685 + create_intf_ep_devs(intf); 1722 1686 } 1723 1687 1724 1688 usb_autosuspend_device(dev);
+1 -21
drivers/usb/core/sysfs.c
··· 629 629 struct device *dev = &udev->dev; 630 630 int retval; 631 631 632 - /* Unforunately these attributes cannot be created before 633 - * the uevent is broadcast. 634 - */ 635 632 retval = device_create_bin_file(dev, &dev_bin_attr_descriptors); 636 633 if (retval) 637 634 goto error; ··· 640 643 retval = add_power_attributes(dev); 641 644 if (retval) 642 645 goto error; 643 - 644 - retval = usb_create_ep_files(dev, &udev->ep0, udev); 645 - if (retval) 646 - goto error; 647 - return 0; 646 + return retval; 648 647 error: 649 648 usb_remove_sysfs_dev_files(udev); 650 649 return retval; ··· 650 657 { 651 658 struct device *dev = &udev->dev; 652 659 653 - usb_remove_ep_files(&udev->ep0); 654 660 remove_power_attributes(dev); 655 661 remove_persist_attributes(dev); 656 662 device_remove_bin_file(dev, &dev_bin_attr_descriptors); ··· 808 816 { 809 817 struct usb_device *udev = interface_to_usbdev(intf); 810 818 struct usb_host_interface *alt = intf->cur_altsetting; 811 - int i; 812 819 int retval; 813 820 814 821 if (intf->sysfs_files_created || intf->unregistering) 815 822 return 0; 816 823 817 - /* The interface string may be present in some altsettings 818 - * and missing in others. Hence its attribute cannot be created 819 - * before the uevent is broadcast. 820 - */ 821 824 if (alt->string == NULL) 822 825 alt->string = usb_cache_string(udev, alt->desc.iInterface); 823 826 if (alt->string) 824 827 retval = device_create_file(&intf->dev, &dev_attr_interface); 825 - for (i = 0; i < alt->desc.bNumEndpoints; ++i) 826 - usb_create_ep_files(&intf->dev, &alt->endpoint[i], udev); 827 828 intf->sysfs_files_created = 1; 828 829 return 0; 829 830 } 830 831 831 832 void usb_remove_sysfs_intf_files(struct usb_interface *intf) 832 833 { 833 - struct usb_host_interface *alt = intf->cur_altsetting; 834 - int i; 835 - 836 834 if (!intf->sysfs_files_created) 837 835 return; 838 836 839 - for (i = 0; i < alt->desc.bNumEndpoints; ++i) 840 - usb_remove_ep_files(&alt->endpoint[i]); 841 837 device_remove_file(&intf->dev, &dev_attr_interface); 842 838 intf->sysfs_files_created = 0; 843 839 }
+37
drivers/usb/core/usb.c
··· 971 971 EXPORT_SYMBOL_GPL(usb_disabled); 972 972 973 973 /* 974 + * Notifications of device and interface registration 975 + */ 976 + static 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 + 1000 + static struct notifier_block usb_bus_nb = { 1001 + .notifier_call = usb_bus_notify, 1002 + }; 1003 + 1004 + /* 974 1005 * Init 975 1006 */ 976 1007 static int __init usb_init(void) ··· 1018 987 retval = bus_register(&usb_bus_type); 1019 988 if (retval) 1020 989 goto bus_register_failed; 990 + retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); 991 + if (retval) 992 + goto bus_notifier_failed; 1021 993 retval = usb_host_init(); 1022 994 if (retval) 1023 995 goto host_init_failed; ··· 1055 1021 major_init_failed: 1056 1022 usb_host_cleanup(); 1057 1023 host_init_failed: 1024 + bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); 1025 + bus_notifier_failed: 1058 1026 bus_unregister(&usb_bus_type); 1059 1027 bus_register_failed: 1060 1028 ksuspend_usb_cleanup(); ··· 1080 1044 usb_devio_cleanup(); 1081 1045 usb_hub_cleanup(); 1082 1046 usb_host_cleanup(); 1047 + bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); 1083 1048 bus_unregister(&usb_bus_type); 1084 1049 ksuspend_usb_cleanup(); 1085 1050 }
+2 -2
drivers/usb/core/usb.h
··· 6 6 extern void usb_remove_sysfs_dev_files(struct usb_device *dev); 7 7 extern int usb_create_sysfs_intf_files(struct usb_interface *intf); 8 8 extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); 9 - extern int usb_create_ep_files(struct device *parent, 9 + extern int usb_create_ep_devs(struct device *parent, 10 10 struct usb_host_endpoint *endpoint, 11 11 struct usb_device *udev); 12 - extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); 12 + extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint); 13 13 14 14 extern void usb_enable_endpoint(struct usb_device *dev, 15 15 struct usb_host_endpoint *ep);
+2
include/linux/usb.h
··· 108 108 * (in probe()), bound to a driver, or unbinding (in disconnect()) 109 109 * @is_active: flag set when the interface is bound and not suspended. 110 110 * @sysfs_files_created: sysfs attributes exist 111 + * @ep_devs_created: endpoint child pseudo-devices exist 111 112 * @unregistering: flag set when the interface is being unregistered 112 113 * @needs_remote_wakeup: flag set when the driver requires remote-wakeup 113 114 * capability during autosuspend. ··· 170 169 enum usb_interface_condition condition; /* state of binding */ 171 170 unsigned is_active:1; /* the interface is not suspended */ 172 171 unsigned sysfs_files_created:1; /* the sysfs attributes exist */ 172 + unsigned ep_devs_created:1; /* endpoint "devices" exist */ 173 173 unsigned unregistering:1; /* unregistration is in progress */ 174 174 unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */ 175 175 unsigned needs_altsetting0:1; /* switch to altsetting 0 is pending */