diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/storage/scsiglue.c | 4 | ||||
-rw-r--r-- | drivers/usb/storage/transport.c | 50 | ||||
-rw-r--r-- | drivers/usb/storage/usb.c | 33 |
3 files changed, 59 insertions, 28 deletions
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 5f11e19eaae3..5715291ba540 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c | |||
@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb) | |||
286 | int result; | 286 | int result; |
287 | 287 | ||
288 | US_DEBUGP("%s called\n", __FUNCTION__); | 288 | US_DEBUGP("%s called\n", __FUNCTION__); |
289 | |||
290 | mutex_lock(&(us->dev_mutex)); | ||
291 | result = usb_stor_port_reset(us); | 289 | result = usb_stor_port_reset(us); |
292 | mutex_unlock(&us->dev_mutex); | ||
293 | |||
294 | return result < 0 ? FAILED : SUCCESS; | 290 | return result < 0 ? FAILED : SUCCESS; |
295 | } | 291 | } |
296 | 292 | ||
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 038f4582ca0b..19b25c5cafd4 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c | |||
@@ -703,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
703 | * device reset. */ | 703 | * device reset. */ |
704 | Handle_Errors: | 704 | Handle_Errors: |
705 | 705 | ||
706 | /* Let the SCSI layer know we are doing a reset, set the | 706 | /* Set the RESETTING bit, and clear the ABORTING bit so that |
707 | * RESETTING bit, and clear the ABORTING bit so that the reset | 707 | * the reset may proceed. */ |
708 | * may proceed. */ | ||
709 | scsi_lock(us_to_host(us)); | 708 | scsi_lock(us_to_host(us)); |
710 | usb_stor_report_bus_reset(us); | ||
711 | set_bit(US_FLIDX_RESETTING, &us->flags); | 709 | set_bit(US_FLIDX_RESETTING, &us->flags); |
712 | clear_bit(US_FLIDX_ABORTING, &us->flags); | 710 | clear_bit(US_FLIDX_ABORTING, &us->flags); |
713 | scsi_unlock(us_to_host(us)); | 711 | scsi_unlock(us_to_host(us)); |
714 | 712 | ||
713 | /* We must release the device lock because the pre_reset routine | ||
714 | * will want to acquire it. */ | ||
715 | mutex_unlock(&us->dev_mutex); | ||
715 | result = usb_stor_port_reset(us); | 716 | result = usb_stor_port_reset(us); |
717 | mutex_lock(&us->dev_mutex); | ||
718 | |||
716 | if (result < 0) { | 719 | if (result < 0) { |
717 | scsi_lock(us_to_host(us)); | 720 | scsi_lock(us_to_host(us)); |
718 | usb_stor_report_device_reset(us); | 721 | usb_stor_report_device_reset(us); |
@@ -1196,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us) | |||
1196 | 0, us->ifnum, NULL, 0); | 1199 | 0, us->ifnum, NULL, 0); |
1197 | } | 1200 | } |
1198 | 1201 | ||
1199 | /* Issue a USB port reset to the device. But don't do anything if | 1202 | /* Issue a USB port reset to the device. The caller must not hold |
1200 | * there's more than one interface in the device, so that other users | 1203 | * us->dev_mutex. |
1201 | * are not affected. */ | 1204 | */ |
1202 | int usb_stor_port_reset(struct us_data *us) | 1205 | int usb_stor_port_reset(struct us_data *us) |
1203 | { | 1206 | { |
1204 | int result, rc; | 1207 | int result, rc_lock; |
1205 | 1208 | ||
1206 | if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { | 1209 | result = rc_lock = |
1207 | result = -EIO; | 1210 | usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); |
1208 | US_DEBUGP("No reset during disconnect\n"); | 1211 | if (result < 0) |
1209 | } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { | 1212 | US_DEBUGP("unable to lock device for reset: %d\n", result); |
1210 | result = -EBUSY; | 1213 | else { |
1211 | US_DEBUGP("Refusing to reset a multi-interface device\n"); | 1214 | /* Were we disconnected while waiting for the lock? */ |
1212 | } else { | 1215 | if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { |
1213 | result = rc = | 1216 | result = -EIO; |
1214 | usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); | 1217 | US_DEBUGP("No reset during disconnect\n"); |
1215 | if (result < 0) { | ||
1216 | US_DEBUGP("unable to lock device for reset: %d\n", | ||
1217 | result); | ||
1218 | } else { | 1218 | } else { |
1219 | result = usb_reset_device(us->pusb_dev); | 1219 | result = usb_reset_composite_device( |
1220 | if (rc) | 1220 | us->pusb_dev, us->pusb_intf); |
1221 | usb_unlock_device(us->pusb_dev); | 1221 | US_DEBUGP("usb_reset_composite_device returns %d\n", |
1222 | US_DEBUGP("usb_reset_device returns %d\n", result); | 1222 | result); |
1223 | } | 1223 | } |
1224 | if (rc_lock) | ||
1225 | usb_unlock_device(us->pusb_dev); | ||
1224 | } | 1226 | } |
1225 | return result; | 1227 | return result; |
1226 | } | 1228 | } |
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 0142fe82f6b8..e232c7c89909 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -221,6 +221,37 @@ static int storage_resume(struct usb_interface *iface) | |||
221 | #endif /* CONFIG_PM */ | 221 | #endif /* CONFIG_PM */ |
222 | 222 | ||
223 | /* | 223 | /* |
224 | * The next two routines get called just before and just after | ||
225 | * a USB port reset, whether from this driver or a different one. | ||
226 | */ | ||
227 | |||
228 | static void storage_pre_reset(struct usb_interface *iface) | ||
229 | { | ||
230 | struct us_data *us = usb_get_intfdata(iface); | ||
231 | |||
232 | US_DEBUGP("%s\n", __FUNCTION__); | ||
233 | |||
234 | /* Make sure no command runs during the reset */ | ||
235 | mutex_lock(&us->dev_mutex); | ||
236 | } | ||
237 | |||
238 | static void storage_post_reset(struct usb_interface *iface) | ||
239 | { | ||
240 | struct us_data *us = usb_get_intfdata(iface); | ||
241 | |||
242 | US_DEBUGP("%s\n", __FUNCTION__); | ||
243 | |||
244 | /* Report the reset to the SCSI core */ | ||
245 | scsi_lock(us_to_host(us)); | ||
246 | usb_stor_report_bus_reset(us); | ||
247 | scsi_unlock(us_to_host(us)); | ||
248 | |||
249 | /* FIXME: Notify the subdrivers that they need to reinitialize | ||
250 | * the device */ | ||
251 | mutex_unlock(&us->dev_mutex); | ||
252 | } | ||
253 | |||
254 | /* | ||
224 | * fill_inquiry_response takes an unsigned char array (which must | 255 | * fill_inquiry_response takes an unsigned char array (which must |
225 | * be at least 36 characters) and populates the vendor name, | 256 | * be at least 36 characters) and populates the vendor name, |
226 | * product name, and revision fields. Then the array is copied | 257 | * product name, and revision fields. Then the array is copied |
@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = { | |||
1002 | .suspend = storage_suspend, | 1033 | .suspend = storage_suspend, |
1003 | .resume = storage_resume, | 1034 | .resume = storage_resume, |
1004 | #endif | 1035 | #endif |
1036 | .pre_reset = storage_pre_reset, | ||
1037 | .post_reset = storage_post_reset, | ||
1005 | .id_table = storage_usb_ids, | 1038 | .id_table = storage_usb_ids, |
1006 | }; | 1039 | }; |
1007 | 1040 | ||