diff options
-rw-r--r-- | drivers/usb/core/endpoint.c | 4 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 18 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 50 | ||||
-rw-r--r-- | drivers/usb/core/sysfs.c | 22 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 37 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 4 | ||||
-rw-r--r-- | include/linux/usb.h | 2 |
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 | ||
279 | int usb_create_ep_files(struct device *parent, | 279 | int 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 | ||
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 | 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 | ||
1670 | fail: | 1664 | fail: |
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 | } |
1005 | EXPORT_SYMBOL_GPL(usb_clear_halt); | 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 | * 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 | } |
1280 | EXPORT_SYMBOL_GPL(usb_set_interface); | 1311 | EXPORT_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; | ||
651 | error: | 644 | error: |
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 | ||
839 | void usb_remove_sysfs_intf_files(struct usb_interface *intf) | 824 | void 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) | |||
971 | EXPORT_SYMBOL_GPL(usb_disabled); | 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 | * Init | 1005 | * Init |
975 | */ | 1006 | */ |
976 | static int __init usb_init(void) | 1007 | static 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: | |||
1021 | major_init_failed: | 1055 | major_init_failed: |
1022 | usb_host_cleanup(); | 1056 | usb_host_cleanup(); |
1023 | host_init_failed: | 1057 | host_init_failed: |
1058 | bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); | ||
1059 | bus_notifier_failed: | ||
1024 | bus_unregister(&usb_bus_type); | 1060 | bus_unregister(&usb_bus_type); |
1025 | bus_register_failed: | 1061 | bus_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); | |||
6 | extern void usb_remove_sysfs_dev_files(struct usb_device *dev); | 6 | extern void usb_remove_sysfs_dev_files(struct usb_device *dev); |
7 | extern int usb_create_sysfs_intf_files(struct usb_interface *intf); | 7 | extern int usb_create_sysfs_intf_files(struct usb_interface *intf); |
8 | extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); | 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 | struct usb_host_endpoint *endpoint, | 10 | struct usb_host_endpoint *endpoint, |
11 | struct usb_device *udev); | 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 | extern void usb_enable_endpoint(struct usb_device *dev, | 14 | extern 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 */ |