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; }