Quellcode durchsuchen

[PATCH] usb-storage: use usb_reset_composite_device

This patch (as701) modifies usb-storage to take advantage of the new
usb_reset_composite_device() API.  Now we will be able to safely request
port resets even if other drivers are bound to a mass-storage device.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Alan Stern vor 19 Jahren
Ursprung
Commit
47104b0dd3
3 geänderte Dateien mit 59 neuen und 28 gelöschten Zeilen
  1. 0 4
      drivers/usb/storage/scsiglue.c
  2. 26 24
      drivers/usb/storage/transport.c
  3. 33 0
      drivers/usb/storage/usb.c

+ 0 - 4
drivers/usb/storage/scsiglue.c

@@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb)
 	int result;
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
-
-	mutex_lock(&(us->dev_mutex));
 	result = usb_stor_port_reset(us);
-	mutex_unlock(&us->dev_mutex);
-
 	return result < 0 ? FAILED : SUCCESS;
 }
 

+ 26 - 24
drivers/usb/storage/transport.c

@@ -703,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 	 * device reset. */
   Handle_Errors:
 
-	/* Let the SCSI layer know we are doing a reset, set the
-	 * RESETTING bit, and clear the ABORTING bit so that the reset
-	 * may proceed. */
+	/* Set the RESETTING bit, and clear the ABORTING bit so that
+	 * the reset may proceed. */
 	scsi_lock(us_to_host(us));
-	usb_stor_report_bus_reset(us);
 	set_bit(US_FLIDX_RESETTING, &us->flags);
 	clear_bit(US_FLIDX_ABORTING, &us->flags);
 	scsi_unlock(us_to_host(us));
 
+	/* We must release the device lock because the pre_reset routine
+	 * will want to acquire it. */
+	mutex_unlock(&us->dev_mutex);
 	result = usb_stor_port_reset(us);
+	mutex_lock(&us->dev_mutex);
+
 	if (result < 0) {
 		scsi_lock(us_to_host(us));
 		usb_stor_report_device_reset(us);
@@ -1196,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us)
 				 0, us->ifnum, NULL, 0);
 }
 
-/* Issue a USB port reset to the device.  But don't do anything if
- * there's more than one interface in the device, so that other users
- * are not affected. */
+/* Issue a USB port reset to the device.  The caller must not hold
+ * us->dev_mutex.
+ */
 int usb_stor_port_reset(struct us_data *us)
 {
-	int result, rc;
+	int result, rc_lock;
 
-	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
-		result = -EIO;
-		US_DEBUGP("No reset during disconnect\n");
-	} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
-		result = -EBUSY;
-		US_DEBUGP("Refusing to reset a multi-interface device\n");
-	} else {
-		result = rc =
-			usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
-		if (result < 0) {
-			US_DEBUGP("unable to lock device for reset: %d\n",
-					result);
+	result = rc_lock =
+		usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+	if (result < 0)
+		US_DEBUGP("unable to lock device for reset: %d\n", result);
+	else {
+		/* Were we disconnected while waiting for the lock? */
+		if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+			result = -EIO;
+			US_DEBUGP("No reset during disconnect\n");
 		} else {
-			result = usb_reset_device(us->pusb_dev);
-			if (rc)
-				usb_unlock_device(us->pusb_dev);
-			US_DEBUGP("usb_reset_device returns %d\n", result);
+			result = usb_reset_composite_device(
+					us->pusb_dev, us->pusb_intf);
+			US_DEBUGP("usb_reset_composite_device returns %d\n",
+					result);
 		}
+		if (rc_lock)
+			usb_unlock_device(us->pusb_dev);
 	}
 	return result;
 }

+ 33 - 0
drivers/usb/storage/usb.c

@@ -220,6 +220,37 @@ static int storage_resume(struct usb_interface *iface)
 
 #endif /* CONFIG_PM */
 
+/*
+ * The next two routines get called just before and just after
+ * a USB port reset, whether from this driver or a different one.
+ */
+
+static void storage_pre_reset(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	US_DEBUGP("%s\n", __FUNCTION__);
+
+	/* Make sure no command runs during the reset */
+	mutex_lock(&us->dev_mutex);
+}
+
+static void storage_post_reset(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	US_DEBUGP("%s\n", __FUNCTION__);
+
+	/* Report the reset to the SCSI core */
+	scsi_lock(us_to_host(us));
+	usb_stor_report_bus_reset(us);
+	scsi_unlock(us_to_host(us));
+
+	/* FIXME: Notify the subdrivers that they need to reinitialize
+	 * the device */
+	mutex_unlock(&us->dev_mutex);
+}
+
 /*
  * fill_inquiry_response takes an unsigned char array (which must
  * be at least 36 characters) and populates the vendor name,
@@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = {
 	.suspend =	storage_suspend,
 	.resume =	storage_resume,
 #endif
+	.pre_reset =	storage_pre_reset,
+	.post_reset =	storage_post_reset,
 	.id_table =	storage_usb_ids,
 };