diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2006-06-01 13:33:42 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-06-21 18:04:15 -0400 |
commit | 79efa097e75018a2918155f343f0e08e61ee8a8c (patch) | |
tree | 336237ca96191aeb9cac6ed8706bc479545f3108 /drivers/usb/core | |
parent | efcaa20525fde82bbb4fb8cd9e9016f6fabc6509 (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/usb/core')
-rw-r--r-- | drivers/usb/core/devio.c | 3 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 84 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 1 |
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 | ||
824 | static int proc_resetdevice(struct dev_state *ps) | 824 | static 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 | ||
830 | static int proc_setintf(struct dev_state *ps, void __user *arg) | 829 | static 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 | */ | ||
3150 | int 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); | |||
1207 | EXPORT_SYMBOL(usb_altnum_to_altsetting); | 1207 | EXPORT_SYMBOL(usb_altnum_to_altsetting); |
1208 | 1208 | ||
1209 | EXPORT_SYMBOL(usb_reset_device); | 1209 | EXPORT_SYMBOL(usb_reset_device); |
1210 | EXPORT_SYMBOL(usb_reset_composite_device); | ||
1210 | 1211 | ||
1211 | EXPORT_SYMBOL(__usb_get_extra_descriptor); | 1212 | EXPORT_SYMBOL(__usb_get_extra_descriptor); |
1212 | 1213 | ||