aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-06-01 13:33:42 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 18:04:15 -0400
commit79efa097e75018a2918155f343f0e08e61ee8a8c (patch)
tree336237ca96191aeb9cac6ed8706bc479545f3108 /drivers
parentefcaa20525fde82bbb4fb8cd9e9016f6fabc6509 (diff)
[PATCH] usbcore: port reset for composite devices
This patch (as699) adds usb_reset_composite_device(), a routine for sending a USB port reset to a device with multiple interfaces owned by different drivers. Drivers are notified about impending and completed resets through two new methods in the usb_driver structure. The patch modifieds the usbfs ioctl code to make it use the new routine instead of usb_reset_device(). Follow-up patches will modify the hub, usb-storage, and usbhid drivers so they can utilize this new API. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/devio.c3
-rw-r--r--drivers/usb/core/hub.c84
-rw-r--r--drivers/usb/core/usb.c1
3 files changed, 83 insertions, 5 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index b04ede772f2c..df3fb57d71e6 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -823,8 +823,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)
823 823
824static int proc_resetdevice(struct dev_state *ps) 824static int proc_resetdevice(struct dev_state *ps)
825{ 825{
826 return usb_reset_device(ps->dev); 826 return usb_reset_composite_device(ps->dev, NULL);
827
828} 827}
829 828
830static int proc_setintf(struct dev_state *ps, void __user *arg) 829static int proc_setintf(struct dev_state *ps, void __user *arg)
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f41c08946a52..37c67d7e8b84 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -3007,9 +3007,9 @@ static int config_descriptors_changed(struct usb_device *udev)
3007 * usb_reset_device - perform a USB port reset to reinitialize a device 3007 * usb_reset_device - perform a USB port reset to reinitialize a device
3008 * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) 3008 * @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
3009 * 3009 *
3010 * WARNING - don't reset any device unless drivers for all of its 3010 * WARNING - don't use this routine to reset a composite device
3011 * interfaces are expecting that reset! Maybe some driver->reset() 3011 * (one with multiple interfaces owned by separate drivers)!
3012 * method should eventually help ensure sufficient cooperation. 3012 * Use usb_reset_composite_device() instead.
3013 * 3013 *
3014 * Do a port reset, reassign the device's address, and establish its 3014 * Do a port reset, reassign the device's address, and establish its
3015 * former operating configuration. If the reset fails, or the device's 3015 * former operating configuration. If the reset fails, or the device's
@@ -3125,3 +3125,81 @@ re_enumerate:
3125 hub_port_logical_disconnect(parent_hub, port1); 3125 hub_port_logical_disconnect(parent_hub, port1);
3126 return -ENODEV; 3126 return -ENODEV;
3127} 3127}
3128
3129/**
3130 * usb_reset_composite_device - warn interface drivers and perform a USB port reset
3131 * @udev: device to reset (not in SUSPENDED or NOTATTACHED state)
3132 * @iface: interface bound to the driver making the request (optional)
3133 *
3134 * Warns all drivers bound to registered interfaces (using their pre_reset
3135 * method), performs the port reset, and then lets the drivers know that
3136 * the reset is over (using their post_reset method).
3137 *
3138 * Return value is the same as for usb_reset_device().
3139 *
3140 * The caller must own the device lock. For example, it's safe to use
3141 * this from a driver probe() routine after downloading new firmware.
3142 * For calls that might not occur during probe(), drivers should lock
3143 * the device using usb_lock_device_for_reset().
3144 *
3145 * The interface locks are acquired during the pre_reset stage and released
3146 * during the post_reset stage. However if iface is not NULL and is
3147 * currently being probed, we assume that the caller already owns its
3148 * lock.
3149 */
3150int usb_reset_composite_device(struct usb_device *udev,
3151 struct usb_interface *iface)
3152{
3153 int ret;
3154 struct usb_host_config *config = udev->actconfig;
3155
3156 if (udev->state == USB_STATE_NOTATTACHED ||
3157 udev->state == USB_STATE_SUSPENDED) {
3158 dev_dbg(&udev->dev, "device reset not allowed in state %d\n",
3159 udev->state);
3160 return -EINVAL;
3161 }
3162
3163 if (iface && iface->condition != USB_INTERFACE_BINDING)
3164 iface = NULL;
3165
3166 if (config) {
3167 int i;
3168 struct usb_interface *cintf;
3169 struct usb_driver *drv;
3170
3171 for (i = 0; i < config->desc.bNumInterfaces; ++i) {
3172 cintf = config->interface[i];
3173 if (cintf != iface)
3174 down(&cintf->dev.sem);
3175 if (device_is_registered(&cintf->dev) &&
3176 cintf->dev.driver) {
3177 drv = to_usb_driver(cintf->dev.driver);
3178 if (drv->pre_reset)
3179 (drv->pre_reset)(cintf);
3180 }
3181 }
3182 }
3183
3184 ret = usb_reset_device(udev);
3185
3186 if (config) {
3187 int i;
3188 struct usb_interface *cintf;
3189 struct usb_driver *drv;
3190
3191 for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
3192 cintf = config->interface[i];
3193 if (device_is_registered(&cintf->dev) &&
3194 cintf->dev.driver) {
3195 drv = to_usb_driver(cintf->dev.driver);
3196 if (drv->post_reset)
3197 (drv->post_reset)(cintf);
3198 }
3199 if (cintf != iface)
3200 up(&cintf->dev.sem);
3201 }
3202 }
3203
3204 return ret;
3205}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index b7fdc1cd134a..515310751303 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1207,6 +1207,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if);
1207EXPORT_SYMBOL(usb_altnum_to_altsetting); 1207EXPORT_SYMBOL(usb_altnum_to_altsetting);
1208 1208
1209EXPORT_SYMBOL(usb_reset_device); 1209EXPORT_SYMBOL(usb_reset_device);
1210EXPORT_SYMBOL(usb_reset_composite_device);
1210 1211
1211EXPORT_SYMBOL(__usb_get_extra_descriptor); 1212EXPORT_SYMBOL(__usb_get_extra_descriptor);
1212 1213