aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/devio.c3
-rw-r--r--drivers/usb/core/hub.c84
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--include/linux/usb.h9
4 files changed, 92 insertions, 5 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index b04ede772f2..df3fb57d71e 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 f41c08946a5..37c67d7e8b8 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 b7fdc1cd134..51531075130 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
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 317ec9f28bc..5ad30cefe7b 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -386,6 +386,8 @@ extern int usb_lock_device_for_reset(struct usb_device *udev,
386 386
387/* USB port reset for device reinitialization */ 387/* USB port reset for device reinitialization */
388extern int usb_reset_device(struct usb_device *dev); 388extern int usb_reset_device(struct usb_device *dev);
389extern int usb_reset_composite_device(struct usb_device *dev,
390 struct usb_interface *iface);
389 391
390extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); 392extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
391 393
@@ -554,6 +556,10 @@ struct usb_dynids {
554 * do (or don't) show up otherwise in the filesystem. 556 * do (or don't) show up otherwise in the filesystem.
555 * @suspend: Called when the device is going to be suspended by the system. 557 * @suspend: Called when the device is going to be suspended by the system.
556 * @resume: Called when the device is being resumed by the system. 558 * @resume: Called when the device is being resumed by the system.
559 * @pre_reset: Called by usb_reset_composite_device() when the device
560 * is about to be reset.
561 * @post_reset: Called by usb_reset_composite_device() after the device
562 * has been reset.
557 * @id_table: USB drivers use ID table to support hotplugging. 563 * @id_table: USB drivers use ID table to support hotplugging.
558 * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set 564 * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set
559 * or your driver's probe function will never get called. 565 * or your driver's probe function will never get called.
@@ -592,6 +598,9 @@ struct usb_driver {
592 int (*suspend) (struct usb_interface *intf, pm_message_t message); 598 int (*suspend) (struct usb_interface *intf, pm_message_t message);
593 int (*resume) (struct usb_interface *intf); 599 int (*resume) (struct usb_interface *intf);
594 600
601 void (*pre_reset) (struct usb_interface *intf);
602 void (*post_reset) (struct usb_interface *intf);
603
595 const struct usb_device_id *id_table; 604 const struct usb_device_id *id_table;
596 605
597 struct usb_dynids dynids; 606 struct usb_dynids dynids;