This patch (as930) implements autosuspend for usb-storage.  It is
adapted from a patch by Oliver Neukum.  Autosuspend is allowed except
during LUN scanning, resets, and command execution.

Signed-off-by: Alan Stern <[EMAIL PROTECTED]>

---

The default autosuspend delay of 2 seconds is probably too low for 
anything other than flash media, and maybe even for that.  Still, the 
best course is to get the patch out there so people can start testing 
it.  If the delay needs to be increased we can take care of it later.

Alan Stern


Index: usb-2.6/drivers/usb/storage/scsiglue.c
===================================================================
--- usb-2.6.orig/drivers/usb/storage/scsiglue.c
+++ usb-2.6/drivers/usb/storage/scsiglue.c
@@ -285,10 +285,15 @@ static int device_reset(struct scsi_cmnd
 
        US_DEBUGP("%s called\n", __FUNCTION__);
 
-       /* lock the device pointers and do the reset */
-       mutex_lock(&(us->dev_mutex));
-       result = us->transport_reset(us);
-       mutex_unlock(&us->dev_mutex);
+       result = usb_autopm_get_interface(us->pusb_intf);
+       if (result == 0) {
+
+               /* lock the device pointers and do the reset */
+               mutex_lock(&(us->dev_mutex));
+               result = us->transport_reset(us);
+               mutex_unlock(&us->dev_mutex);
+               usb_autopm_put_interface(us->pusb_intf);
+       }
 
        return result < 0 ? FAILED : SUCCESS;
 }
Index: usb-2.6/drivers/usb/storage/usb.c
===================================================================
--- usb-2.6.orig/drivers/usb/storage/usb.c
+++ usb-2.6/drivers/usb/storage/usb.c
@@ -191,16 +191,14 @@ static int storage_suspend(struct usb_in
 {
        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);
 
-       /* 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;
 }
@@ -209,13 +207,11 @@ 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);
 
-       mutex_unlock(&us->dev_mutex);
        return 0;
 }
 
@@ -313,6 +309,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 autopm_rc;
 
        current->flags |= PF_NOFREEZE;
 
@@ -323,6 +320,9 @@ static int usb_stor_control_thread(void 
                        
                US_DEBUGP("*** thread awakened.\n");
 
+               /* Autoresume the device */
+               autopm_rc = usb_autopm_get_interface_burst(us->pusb_intf);
+
                /* lock the device pointers */
                mutex_lock(&(us->dev_mutex));
 
@@ -381,6 +381,12 @@ static int usb_stor_control_thread(void 
                        us->srb->result = SAM_STAT_GOOD;
                }
 
+               /* Did the autoresume fail? */
+               else if (autopm_rc < 0) {
+                       US_DEBUGP("Could not wake device\n");
+                       us->srb->result = DID_ERROR << 16;
+               }
+
                /* we've got a command, let's do it! */
                else {
                        US_DEBUG(usb_stor_show_command(us->srb));
@@ -423,6 +429,10 @@ SkipForAbort:
 
                /* unlock the device pointers */
                mutex_unlock(&us->dev_mutex);
+
+               /* Start an autosuspend */
+               if (autopm_rc == 0)
+                       usb_autopm_put_interface(us->pusb_intf);
        } /* for (;;) */
 
        /* Wait until we are told to stop */
@@ -939,6 +949,7 @@ retry:
        }
 
        scsi_host_put(us_to_host(us));
+       usb_autopm_put_interface(us->pusb_intf);
        complete_and_exit(&threads_gone, 0);
 }
 
@@ -1028,6 +1039,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;
@@ -1065,6 +1077,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/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to