[patch]autosuspend for usb storage

Oliver Neukum <[email protected]>
Newsgroups gmane.linux.usb.devel
Organization Novell
Message-ID <[email protected]>
Hi,

this patch implements autosuspend for usb-storage.
The device may autosuspend except while
1. a scsi request is being processed
2. a bus is scanned for devices
3. a scsi reset is in progress

	Regards
		Oliver
Signed-off-by: Oliver Neukum <[email protected]>
-- 

--- linux-2.6.21-rc7/drivers/usb/storage/scsiglue.c	2007-04-25 08:48:23.000000000 +0200
+++ linux-2.6.21-rc7-auto/drivers/usb/storage/scsiglue.c	2007-04-25 08:56:08.000000000 +0200
@@ -287,7 +287,11 @@ static int device_reset(struct scsi_cmnd
 
 	/* lock the device pointers and do the reset */
 	mutex_lock(&(us->dev_mutex));
-	result = us->transport_reset(us);
+	result = usb_autopm_get_interface(us->pusb_intf);
+	if (!result) {
+		result = us->transport_reset(us);
+		usb_autopm_put_interface(us->pusb_intf);
+	}
 	mutex_unlock(&us->dev_mutex);
 
 	return result < 0 ? FAILED : SUCCESS;
--- linux-2.6.21-rc7/drivers/usb/storage/usb.c	2007-04-25 08:48:23.000000000 +0200
+++ linux-2.6.21-rc7-auto/drivers/usb/storage/usb.c	2007-04-24 14:03:56.000000000 +0200
@@ -68,6 +68,8 @@
 #include "debug.h"
 #include "initializers.h"
 
+#include "../core/usb.h"
+
 #ifdef CONFIG_USB_STORAGE_USBAT
 #include "shuttle_usbat.h"
 #endif
@@ -190,19 +192,19 @@ static struct us_unusual_dev us_unusual_
 static int storage_suspend(struct usb_interface *iface, pm_message_t message)
 {
 	struct us_data *us = usb_get_intfdata(iface);
+	US_DEBUGP("%s\n", __FUNCTION__);
 
 	/* Wait until no command is running */
 	mutex_lock(&us->dev_mutex);
 
-	US_DEBUGP("%s\n", __FUNCTION__);
 	if (us->suspend_resume_hook)
 		(us->suspend_resume_hook)(us, US_SUSPEND);
 	iface->dev.power.power_state.event = message.event;
 
 	/* When runtime PM is working, we'll set a flag to indicate
 	 * whether we should autoresume when a SCSI request arrives. */
-
 	mutex_unlock(&us->dev_mutex);
+
 	return 0;
 }
 
@@ -210,14 +212,12 @@ static int storage_resume(struct usb_int
 {
 	struct us_data *us = usb_get_intfdata(iface);
 
-	mutex_lock(&us->dev_mutex);
-
 	US_DEBUGP("%s\n", __FUNCTION__);
+
 	if (us->suspend_resume_hook)
 		(us->suspend_resume_hook)(us, US_RESUME);
 	iface->dev.power.power_state.event = PM_EVENT_ON;
 
-	mutex_unlock(&us->dev_mutex);
 	return 0;
 }
 
@@ -300,6 +300,7 @@ static int usb_stor_control_thread(void 
 {
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
+	int res;
 
 	current->flags |= PF_NOFREEZE;
 
@@ -311,6 +312,7 @@ static int usb_stor_control_thread(void 
 		US_DEBUGP("*** thread awakened.\n");
 
 		/* lock the device pointers */
+		usb_pm_lock(us->pusb_dev);
 		mutex_lock(&(us->dev_mutex));
 
 		/* if the device has disconnected, we are free to exit */
@@ -370,8 +372,15 @@ static int usb_stor_control_thread(void 
 
 		/* we've got a command, let's do it! */
 		else {
-			US_DEBUG(usb_stor_show_command(us->srb));
-			us->proto_handler(us->srb, us);
+			res = __usb_autopm_do_interface(us->pusb_intf, 1);
+			if (!res) {
+				US_DEBUG(usb_stor_show_command(us->srb));
+				us->proto_handler(us->srb, us);
+				__usb_autopm_do_interface(us->pusb_intf, -1);
+			} else {
+				us->srb->result = DID_ERROR << 16;
+				US_DEBUGP("Could not wake device\n");
+			}
 		}
 
 		/* lock access to the state */
@@ -410,6 +419,7 @@ SkipForAbort:
 
 		/* unlock the device pointers */
 		mutex_unlock(&us->dev_mutex);
+		usb_pm_unlock(us->pusb_dev);
 	} /* for (;;) */
 
 	scsi_host_put(host);
@@ -938,6 +948,7 @@ retry:
 	}
 
 	scsi_host_put(us_to_host(us));
+	usb_autopm_put_interface(us->pusb_intf);
 	complete_and_exit(&threads_gone, 0);
 }
 
@@ -1027,6 +1038,7 @@ static int storage_probe(struct usb_inte
 	 * start it up. */
 	scsi_host_get(us_to_host(us));
 	atomic_inc(&total_threads);
+	usb_autopm_get_interface(intf); /* dropped in the scanning thread */
 	wake_up_process(th);
 
 	return 0;
@@ -1063,6 +1075,7 @@ static struct usb_driver usb_storage_dri
 	.pre_reset =	storage_pre_reset,
 	.post_reset =	storage_post_reset,
 	.id_table =	storage_usb_ids,
+	.supports_autosuspend = 1,
 };
 
 static int __init usb_stor_init(void)

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.