From inaky@linux.intel.com Thu Sep 7 16:01:51 2006 From: Inaky Perez-Gonzalez To: linux-usb-devel@lists.sourceforge.net Subject: usb: introduce usb_reenumerate_device() Date: Thu, 7 Sep 2006 15:24:16 -0700 Cc: Greg KH , David Brownell Content-Disposition: inline Message-Id: <200609071524.16397.inaky.perez-gonzalez@intel.com> usb: introduce usb_reenumerate_device() This function implements a logical reset which will cause the device to be reenumerated in the USB stack, without physically being disconnected from the bus. This is useful for device-firmware-upload cases where we can't use usb_reset_device() as it would bring the device back to full reset state. Signed-off-by: Inaky Perez-Gonzalez Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 34 ++++++++++++++++++++++++++++++++++ include/linux/usb.h | 1 + 2 files changed, 35 insertions(+) --- gregkh-2.6.orig/drivers/usb/core/hub.c +++ gregkh-2.6/drivers/usb/core/hub.c @@ -3036,3 +3036,37 @@ int usb_reset_composite_device(struct us return ret; } EXPORT_SYMBOL(usb_reset_composite_device); + + +/** + * usb_reenumerate_device - Reenumerate a USB device + * + * @usb_dev: USB device that needs to be reset. + * + * Disconnects the device from the USB bus (without physically doing + * so), forcing a reenumearation. This is useful for + * device-firmware-upload cases where we can't use usb_reset_device() + * as it would bring the device back to full reset state. + */ +int usb_reenumerate_device(struct usb_device *usb_dev) +{ + struct usb_device *parent_hdev = usb_dev->parent; + struct usb_hub *parent_hub; + + if (usb_dev->state == USB_STATE_NOTATTACHED || + usb_dev->state == USB_STATE_SUSPENDED) { + dev_dbg(&usb_dev->dev, + "device reenumeration not allowed in state %d\n", + usb_dev->state); + return -EINVAL; + } + if (!parent_hdev) { + /* this requires hcd-specific logic; see OHCI hc_restart() */ + dev_dbg(&usb_dev->dev, "%s for root hub!\n", __FUNCTION__); + return -EISDIR; + } + parent_hub = hdev_to_hub(parent_hdev); + hub_port_logical_disconnect(parent_hub, usb_dev->portnum); + return 0; +} +EXPORT_SYMBOL_GPL(usb_reenumerate_device); --- gregkh-2.6.orig/include/linux/usb.h +++ gregkh-2.6/include/linux/usb.h @@ -389,6 +389,7 @@ extern int usb_lock_device_for_reset(str extern int usb_reset_device(struct usb_device *dev); extern int usb_reset_composite_device(struct usb_device *dev, struct usb_interface *iface); +extern int usb_reenumerate_device(struct usb_device *usb_dev); extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);