USB: keep track of whether interface sysfs files exist

This patch (as1009) solves the problem of multiple registrations for
USB sysfs files in a more satisfying way than the existing code.  It
simply adds a flag to keep track of whether or not the files have been
created; that way the files can be created or removed as needed.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>

diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 316a746..40fd39d 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1172,7 +1172,6 @@
 	struct usb_host_interface *alt;
 	int ret;
 	int manual = 0;
-	int changed;
 
 	if (dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
@@ -1212,8 +1211,7 @@
 	 */
 
 	/* prevent submissions using previous endpoint settings */
-	changed = (iface->cur_altsetting != alt);
-	if (changed && device_is_registered(&iface->dev))
+	if (iface->cur_altsetting != alt && device_is_registered(&iface->dev))
 		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, iface);
 
@@ -1250,7 +1248,7 @@
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	usb_enable_interface(dev, iface);
-	if (changed && device_is_registered(&iface->dev))
+	if (device_is_registered(&iface->dev))
 		usb_create_sysfs_intf_files(iface);
 
 	return 0;
@@ -1641,12 +1639,6 @@
 				intf->dev.bus_id, ret);
 			continue;
 		}
-
-		/* The driver's probe method can call usb_set_interface(),
-		 * which would mean the interface's sysfs files are already
-		 * created.  Just in case, we'll remove them first.
-		 */
-		usb_remove_sysfs_intf_files(intf);
 		usb_create_sysfs_intf_files(intf);
 	}
 
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index b04afd0..32bd130 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -735,6 +735,8 @@
 	struct usb_host_interface *alt = intf->cur_altsetting;
 	int retval;
 
+	if (intf->sysfs_files_created)
+		return 0;
 	retval = sysfs_create_group(&dev->kobj, &intf_attr_grp);
 	if (retval)
 		return retval;
@@ -746,6 +748,7 @@
 	if (intf->intf_assoc)
 		retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
 	usb_create_intf_ep_files(intf, udev);
+	intf->sysfs_files_created = 1;
 	return 0;
 }
 
@@ -753,8 +756,11 @@
 {
 	struct device *dev = &intf->dev;
 
+	if (!intf->sysfs_files_created)
+		return;
 	usb_remove_intf_ep_files(intf);
 	device_remove_file(dev, &dev_attr_interface);
 	sysfs_remove_group(&dev->kobj, &intf_attr_grp);
 	sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
+	intf->sysfs_files_created = 0;
 }
diff --git a/include/linux/usb.h b/include/linux/usb.h
index c5c8f16..416ee76 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -157,6 +157,7 @@
 					 * bound to */
 	enum usb_interface_condition condition;		/* state of binding */
 	unsigned is_active:1;		/* the interface is not suspended */
+	unsigned sysfs_files_created:1;	/* the sysfs attributes exist */
 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
 
 	struct device dev;		/* interface specific device info */