aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-04-30 15:37:19 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-05-14 13:00:26 -0400
commit2e5f10e4f0a9649186d8a8c793822b2e0dae8373 (patch)
treeb05f66b353cd9537fc031b387c03040d3b92dcc6
parent6986a978eec70c867717fe6bee736f0bd1db1508 (diff)
USB: create attributes before sending uevent
This patch (as1087d) fixes a long-standing problem in usbcore: Device, interface, and endpoint attributes aren't added until _after_ the creation uevent has already been broadcast. Unfortunately there are a few attributes which cannot be created that early. The "descriptors" attribute is binary and so must be created separately. The power-management attributes can't be created until the dev/power/ group exists. And the interface string can vary from one altsetting to another, so it has to be created dynamically. 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>
-rw-r--r--drivers/usb/core/endpoint.c11
-rw-r--r--drivers/usb/core/message.c1
-rw-r--r--drivers/usb/core/sysfs.c137
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/core/usb.h4
5 files changed, 96 insertions, 58 deletions
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 99e5a68a3f12..fae55a31e26d 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -156,6 +156,10 @@ static struct attribute *ep_dev_attrs[] = {
156static struct attribute_group ep_dev_attr_grp = { 156static struct attribute_group ep_dev_attr_grp = {
157 .attrs = ep_dev_attrs, 157 .attrs = ep_dev_attrs,
158}; 158};
159static struct attribute_group *ep_dev_groups[] = {
160 &ep_dev_attr_grp,
161 NULL
162};
159 163
160static int usb_endpoint_major_init(void) 164static int usb_endpoint_major_init(void)
161{ 165{
@@ -298,6 +302,7 @@ int usb_create_ep_files(struct device *parent,
298 302
299 ep_dev->desc = &endpoint->desc; 303 ep_dev->desc = &endpoint->desc;
300 ep_dev->udev = udev; 304 ep_dev->udev = udev;
305 ep_dev->dev.groups = ep_dev_groups;
301 ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor); 306 ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
302 ep_dev->dev.class = ep_class->class; 307 ep_dev->dev.class = ep_class->class;
303 ep_dev->dev.parent = parent; 308 ep_dev->dev.parent = parent;
@@ -309,9 +314,6 @@ int usb_create_ep_files(struct device *parent,
309 retval = device_register(&ep_dev->dev); 314 retval = device_register(&ep_dev->dev);
310 if (retval) 315 if (retval)
311 goto error_chrdev; 316 goto error_chrdev;
312 retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
313 if (retval)
314 goto error_group;
315 317
316 /* create the symlink to the old-style "ep_XX" directory */ 318 /* create the symlink to the old-style "ep_XX" directory */
317 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); 319 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
@@ -322,8 +324,6 @@ int usb_create_ep_files(struct device *parent,
322 return retval; 324 return retval;
323 325
324error_link: 326error_link:
325 sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
326error_group:
327 device_unregister(&ep_dev->dev); 327 device_unregister(&ep_dev->dev);
328 destroy_endpoint_class(); 328 destroy_endpoint_class();
329 return retval; 329 return retval;
@@ -348,7 +348,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
348 348
349 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); 349 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
350 sysfs_remove_link(&ep_dev->dev.parent->kobj, name); 350 sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
351 sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
352 device_unregister(&ep_dev->dev); 351 device_unregister(&ep_dev->dev);
353 endpoint->ep_dev = NULL; 352 endpoint->ep_dev = NULL;
354 destroy_endpoint_class(); 353 destroy_endpoint_class();
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 3e69266e1f4d..fe47d145255a 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1607,6 +1607,7 @@ free_interfaces:
1607 intf->dev.driver = NULL; 1607 intf->dev.driver = NULL;
1608 intf->dev.bus = &usb_bus_type; 1608 intf->dev.bus = &usb_bus_type;
1609 intf->dev.type = &usb_if_device_type; 1609 intf->dev.type = &usb_if_device_type;
1610 intf->dev.groups = usb_interface_groups;
1610 intf->dev.dma_mask = dev->dev.dma_mask; 1611 intf->dev.dma_mask = dev->dev.dma_mask;
1611 device_initialize(&intf->dev); 1612 device_initialize(&intf->dev);
1612 mark_quiesced(intf); 1613 mark_quiesced(intf);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 5b20a60de8ba..c783cb111847 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -538,6 +538,46 @@ static struct attribute_group dev_attr_grp = {
538 .attrs = dev_attrs, 538 .attrs = dev_attrs,
539}; 539};
540 540
541/* When modifying this list, be sure to modify dev_string_attrs_are_visible()
542 * accordingly.
543 */
544static struct attribute *dev_string_attrs[] = {
545 &dev_attr_manufacturer.attr,
546 &dev_attr_product.attr,
547 &dev_attr_serial.attr,
548 NULL
549};
550
551static mode_t dev_string_attrs_are_visible(struct kobject *kobj,
552 struct attribute *a, int n)
553{
554 struct usb_device *udev = to_usb_device(
555 container_of(kobj, struct device, kobj));
556
557 if (a == &dev_attr_manufacturer.attr) {
558 if (udev->manufacturer == NULL)
559 return 0;
560 } else if (a == &dev_attr_product.attr) {
561 if (udev->product == NULL)
562 return 0;
563 } else if (a == &dev_attr_serial.attr) {
564 if (udev->serial == NULL)
565 return 0;
566 }
567 return a->mode;
568}
569
570static struct attribute_group dev_string_attr_grp = {
571 .attrs = dev_string_attrs,
572 .is_visible = dev_string_attrs_are_visible,
573};
574
575struct attribute_group *usb_device_groups[] = {
576 &dev_attr_grp,
577 &dev_string_attr_grp,
578 NULL
579};
580
541/* Binary descriptors */ 581/* Binary descriptors */
542 582
543static ssize_t 583static ssize_t
@@ -591,10 +631,9 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
591 struct device *dev = &udev->dev; 631 struct device *dev = &udev->dev;
592 int retval; 632 int retval;
593 633
594 retval = sysfs_create_group(&dev->kobj, &dev_attr_grp); 634 /* Unforunately these attributes cannot be created before
595 if (retval) 635 * the uevent is broadcast.
596 return retval; 636 */
597
598 retval = device_create_bin_file(dev, &dev_bin_attr_descriptors); 637 retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
599 if (retval) 638 if (retval)
600 goto error; 639 goto error;
@@ -607,21 +646,6 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
607 if (retval) 646 if (retval)
608 goto error; 647 goto error;
609 648
610 if (udev->manufacturer) {
611 retval = device_create_file(dev, &dev_attr_manufacturer);
612 if (retval)
613 goto error;
614 }
615 if (udev->product) {
616 retval = device_create_file(dev, &dev_attr_product);
617 if (retval)
618 goto error;
619 }
620 if (udev->serial) {
621 retval = device_create_file(dev, &dev_attr_serial);
622 if (retval)
623 goto error;
624 }
625 retval = usb_create_ep_files(dev, &udev->ep0, udev); 649 retval = usb_create_ep_files(dev, &udev->ep0, udev);
626 if (retval) 650 if (retval)
627 goto error; 651 goto error;
@@ -636,13 +660,9 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
636 struct device *dev = &udev->dev; 660 struct device *dev = &udev->dev;
637 661
638 usb_remove_ep_files(&udev->ep0); 662 usb_remove_ep_files(&udev->ep0);
639 device_remove_file(dev, &dev_attr_manufacturer);
640 device_remove_file(dev, &dev_attr_product);
641 device_remove_file(dev, &dev_attr_serial);
642 remove_power_attributes(dev); 663 remove_power_attributes(dev);
643 remove_persist_attributes(dev); 664 remove_persist_attributes(dev);
644 device_remove_bin_file(dev, &dev_bin_attr_descriptors); 665 device_remove_bin_file(dev, &dev_bin_attr_descriptors);
645 sysfs_remove_group(&dev->kobj, &dev_attr_grp);
646} 666}
647 667
648/* Interface Accociation Descriptor fields */ 668/* Interface Accociation Descriptor fields */
@@ -688,17 +708,15 @@ static ssize_t show_interface_string(struct device *dev,
688 struct device_attribute *attr, char *buf) 708 struct device_attribute *attr, char *buf)
689{ 709{
690 struct usb_interface *intf; 710 struct usb_interface *intf;
691 struct usb_device *udev; 711 char *string;
692 int len;
693 712
694 intf = to_usb_interface(dev); 713 intf = to_usb_interface(dev);
695 udev = interface_to_usbdev(intf); 714 string = intf->cur_altsetting->string;
696 len = snprintf(buf, 256, "%s", intf->cur_altsetting->string); 715 barrier(); /* The altsetting might change! */
697 if (len < 0) 716
717 if (!string)
698 return 0; 718 return 0;
699 buf[len] = '\n'; 719 return sprintf(buf, "%s\n", string);
700 buf[len+1] = 0;
701 return len+1;
702} 720}
703static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); 721static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
704 722
@@ -727,18 +745,6 @@ static ssize_t show_modalias(struct device *dev,
727} 745}
728static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); 746static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
729 747
730static struct attribute *intf_assoc_attrs[] = {
731 &dev_attr_iad_bFirstInterface.attr,
732 &dev_attr_iad_bInterfaceCount.attr,
733 &dev_attr_iad_bFunctionClass.attr,
734 &dev_attr_iad_bFunctionSubClass.attr,
735 &dev_attr_iad_bFunctionProtocol.attr,
736 NULL,
737};
738static struct attribute_group intf_assoc_attr_grp = {
739 .attrs = intf_assoc_attrs,
740};
741
742static struct attribute *intf_attrs[] = { 748static struct attribute *intf_attrs[] = {
743 &dev_attr_bInterfaceNumber.attr, 749 &dev_attr_bInterfaceNumber.attr,
744 &dev_attr_bAlternateSetting.attr, 750 &dev_attr_bAlternateSetting.attr,
@@ -753,6 +759,37 @@ static struct attribute_group intf_attr_grp = {
753 .attrs = intf_attrs, 759 .attrs = intf_attrs,
754}; 760};
755 761
762static struct attribute *intf_assoc_attrs[] = {
763 &dev_attr_iad_bFirstInterface.attr,
764 &dev_attr_iad_bInterfaceCount.attr,
765 &dev_attr_iad_bFunctionClass.attr,
766 &dev_attr_iad_bFunctionSubClass.attr,
767 &dev_attr_iad_bFunctionProtocol.attr,
768 NULL,
769};
770
771static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
772 struct attribute *a, int n)
773{
774 struct usb_interface *intf = to_usb_interface(
775 container_of(kobj, struct device, kobj));
776
777 if (intf->intf_assoc == NULL)
778 return 0;
779 return a->mode;
780}
781
782static struct attribute_group intf_assoc_attr_grp = {
783 .attrs = intf_assoc_attrs,
784 .is_visible = intf_assoc_attrs_are_visible,
785};
786
787struct attribute_group *usb_interface_groups[] = {
788 &intf_attr_grp,
789 &intf_assoc_attr_grp,
790 NULL
791};
792
756static inline void usb_create_intf_ep_files(struct usb_interface *intf, 793static inline void usb_create_intf_ep_files(struct usb_interface *intf,
757 struct usb_device *udev) 794 struct usb_device *udev)
758{ 795{
@@ -777,23 +814,21 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
777 814
778int usb_create_sysfs_intf_files(struct usb_interface *intf) 815int usb_create_sysfs_intf_files(struct usb_interface *intf)
779{ 816{
780 struct device *dev = &intf->dev;
781 struct usb_device *udev = interface_to_usbdev(intf); 817 struct usb_device *udev = interface_to_usbdev(intf);
782 struct usb_host_interface *alt = intf->cur_altsetting; 818 struct usb_host_interface *alt = intf->cur_altsetting;
783 int retval; 819 int retval;
784 820
785 if (intf->sysfs_files_created) 821 if (intf->sysfs_files_created)
786 return 0; 822 return 0;
787 retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
788 if (retval)
789 return retval;
790 823
824 /* The interface string may be present in some altsettings
825 * and missing in others. Hence its attribute cannot be created
826 * before the uevent is broadcast.
827 */
791 if (alt->string == NULL) 828 if (alt->string == NULL)
792 alt->string = usb_cache_string(udev, alt->desc.iInterface); 829 alt->string = usb_cache_string(udev, alt->desc.iInterface);
793 if (alt->string) 830 if (alt->string)
794 retval = device_create_file(dev, &dev_attr_interface); 831 retval = device_create_file(&intf->dev, &dev_attr_interface);
795 if (intf->intf_assoc)
796 retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
797 usb_create_intf_ep_files(intf, udev); 832 usb_create_intf_ep_files(intf, udev);
798 intf->sysfs_files_created = 1; 833 intf->sysfs_files_created = 1;
799 return 0; 834 return 0;
@@ -807,7 +842,5 @@ void usb_remove_sysfs_intf_files(struct usb_interface *intf)
807 return; 842 return;
808 usb_remove_intf_ep_files(intf); 843 usb_remove_intf_ep_files(intf);
809 device_remove_file(dev, &dev_attr_interface); 844 device_remove_file(dev, &dev_attr_interface);
810 sysfs_remove_group(&dev->kobj, &intf_attr_grp);
811 sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
812 intf->sysfs_files_created = 0; 845 intf->sysfs_files_created = 0;
813} 846}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 1f0db51190cc..325774375837 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -291,6 +291,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
291 device_initialize(&dev->dev); 291 device_initialize(&dev->dev);
292 dev->dev.bus = &usb_bus_type; 292 dev->dev.bus = &usb_bus_type;
293 dev->dev.type = &usb_device_type; 293 dev->dev.type = &usb_device_type;
294 dev->dev.groups = usb_device_groups;
294 dev->dev.dma_mask = bus->controller->dma_mask; 295 dev->dev.dma_mask = bus->controller->dma_mask;
295 set_dev_node(&dev->dev, dev_to_node(bus->controller)); 296 set_dev_node(&dev->dev, dev_to_node(bus->controller));
296 dev->state = USB_STATE_ATTACHED; 297 dev->state = USB_STATE_ATTACHED;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 1bf8ccb9c58d..1a8bc21c335e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -130,6 +130,10 @@ static inline int is_active(const struct usb_interface *f)
130/* for labeling diagnostics */ 130/* for labeling diagnostics */
131extern const char *usbcore_name; 131extern const char *usbcore_name;
132 132
133/* sysfs stuff */
134extern struct attribute_group *usb_device_groups[];
135extern struct attribute_group *usb_interface_groups[];
136
133/* usbfs stuff */ 137/* usbfs stuff */
134extern struct mutex usbfs_mutex; 138extern struct mutex usbfs_mutex;
135extern struct usb_driver usbfs_driver; 139extern struct usb_driver usbfs_driver;