ChangeSet 1.1743.3.16, 2004/05/25 12:27:47-07:00, stern@rowland.harvard.edu

[PATCH] USB: Add usb_release_address() and move usb_set_address()

This patch adds usb_release_address() as a complement to
usb_choose_address(), to centralize the work required when freeing an
allocated device address.  It also moves the usb_set_address() routine
from usb.c to hub.c -- which is the only place it is ever used -- and
renames it to hub_set_address().


 drivers/usb/core/hcd.h |    4 ++--
 drivers/usb/core/hub.c |   20 +++++++++++++++++---
 drivers/usb/core/usb.c |   40 ++++++++++++++++++----------------------
 3 files changed, 37 insertions(+), 27 deletions(-)


diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Fri May 28 14:40:37 2004
+++ b/drivers/usb/core/hcd.h	Fri May 28 14:40:37 2004
@@ -243,13 +243,13 @@
 extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
 					struct usb_bus *, unsigned port);
 extern int usb_new_device(struct usb_device *dev);
-extern void usb_choose_address(struct usb_device *dev);
 extern void usb_disconnect(struct usb_device **);
+extern void usb_choose_address(struct usb_device *dev);
+extern void usb_release_address(struct usb_device *dev);
 
 /* exported to hub driver ONLY to support usb_reset_device () */
 extern int usb_get_configuration(struct usb_device *dev);
 extern void usb_destroy_configuration(struct usb_device *dev);
-extern int usb_set_address(struct usb_device *dev);
 
 /* use these only before the device's address has been set */
 #define usb_snddefctrl(dev)		((PIPE_CONTROL << 30))
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Fri May 28 14:40:37 2004
+++ b/drivers/usb/core/hub.c	Fri May 28 14:40:37 2004
@@ -1030,6 +1030,21 @@
 	return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
 }
 
+static int hub_set_address(struct usb_device *dev)
+{
+	int retval;
+
+	if (dev->devnum == 0)
+		return -EINVAL;
+	if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
+		return -EINVAL;
+	retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
+		0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+	if (retval == 0)
+		dev->state = USB_STATE_ADDRESS;
+	return retval;
+}
+
 /* reset device, (re)assign address, get device descriptor.
  * device connection is stable, no more debouncing needed.
  * returns device in USB_STATE_ADDRESS, except on error.
@@ -1143,7 +1158,7 @@
 	 */
 	for (i = 0; i < GET_DESCRIPTOR_TRIES; ++i) {
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-			retval = usb_set_address(dev);
+			retval = hub_set_address(dev);
 			if (retval >= 0)
 				break;
 			msleep(200);
@@ -1154,8 +1169,7 @@
 				dev->devnum, retval);
  fail:
 			hub_port_disable(hub, port);
-			clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-			dev->devnum = -1;
+			usb_release_address(dev);
 			usb_put_dev(dev);
 			up(&usb_address0_sem);
 			return retval;
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Fri May 28 14:40:37 2004
+++ b/drivers/usb/core/usb.c	Fri May 28 14:40:37 2004
@@ -998,12 +998,10 @@
 	 */
 	usb_disable_device(dev, 0);
 
-	dev_dbg (&dev->dev, "unregistering device\n");
 	/* Free the device number and remove the /proc/bus/usb entry */
-	if (dev->devnum > 0) {
-		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-		usbfs_remove_device(dev);
-	}
+	dev_dbg (&dev->dev, "unregistering device\n");
+	usb_release_address(dev);
+	usbfs_remove_device(dev);
 	up(&dev->serialize);
 	device_unregister(&dev->dev);
 }
@@ -1038,24 +1036,23 @@
 	}
 }
 
-
-// hub-only!! ... and only exported for reset/reinit path.
-// otherwise used internally, for usb_new_device()
-int usb_set_address(struct usb_device *dev)
+/**
+ * usb_release_address - deallocate device address (usbcore-internal)
+ * @dev: newly removed device
+ *
+ * Removes and deallocates the address assigned to a device.
+ * Only hub drivers (but not virtual root hub drivers for host
+ * controllers) should ever call this.
+ */
+void usb_release_address(struct usb_device *dev)
 {
-	int retval;
-
-	if (dev->devnum == 0)
-		return -EINVAL;
-	if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
-		return -EINVAL;
-	retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
-		0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
-	if (retval == 0)
-		dev->state = USB_STATE_ADDRESS;
-	return retval;
+	if (dev->devnum > 0) {
+		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
+		dev->devnum = -1;
+	}
 }
 
+
 static inline void usb_show_string(struct usb_device *dev, char *id, int index)
 {
 	char *buf;
@@ -1166,8 +1163,7 @@
 	return 0;
 fail:
 	dev->state = USB_STATE_NOTATTACHED;
-	clear_bit(dev->devnum, dev->bus->devmap.devicemap);
-	dev->devnum = -1;
+	usb_release_address(dev);
 	usb_put_dev(dev);
 	return err;
 }