This patch implements autosuspend and autoresume for usb-storage.  It 
is based on the SCSI Dynamic PM patch just posted on linux-scsi and 
linux-pm.

Note: For testing, you will have to set the power/level attribute (and 
possibly also power/autosuspend) for both the SCSI device and the USB 
device.

Alan Stern



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
@@ -184,16 +184,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;
 }
@@ -202,13 +200,10 @@ 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;
 }
 
@@ -928,6 +923,7 @@ static int usb_stor_scan_thread(void * _
                /* Should we unbind if no devices were detected? */
        }
 
+       usb_autopm_put_interface(us->pusb_intf);
        complete_and_exit(&us->scanning_done, 0);
 }
 
@@ -957,6 +953,9 @@ static int storage_probe(struct usb_inte
                return -ENOMEM;
        }
 
+       /* Don't autosuspend until the SCSI core tells us */
+       usb_autopm_get_interface(intf);
+
        /*
         * Allow 16-byte CDBs and thus > 2TB
         */
@@ -1017,6 +1016,7 @@ static int storage_probe(struct usb_inte
                goto BadDevice;
        }
 
+       usb_autopm_get_interface(intf); /* dropped in the scanning thread */
        wake_up_process(th);
 
        return 0;
@@ -1054,6 +1054,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)
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
@@ -295,10 +295,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;
 }
@@ -341,6 +346,24 @@ void usb_stor_report_bus_reset(struct us
        scsi_unlock(host);
 }
 
+/* The host and its devices are all idle so we can autosuspend */
+static int autosuspend(struct Scsi_Host *host)
+{
+       struct us_data *us = host_to_us(host);
+
+       usb_autopm_put_interface(us->pusb_intf);
+       return 0;
+}
+
+/* The host needs to be autoresumed */
+static int autoresume(struct Scsi_Host *host)
+{
+       struct us_data *us = host_to_us(host);
+
+       return usb_autopm_get_interface(us->pusb_intf);
+}
+
+
 /***********************************************************************
  * /proc/scsi/ functions
  ***********************************************************************/
@@ -467,6 +490,10 @@ struct scsi_host_template usb_stor_host_
        .eh_device_reset_handler =      device_reset,
        .eh_bus_reset_handler =         bus_reset,
 
+       /* dynamic power management */
+       .autosuspend =                  autosuspend,
+       .autoresume =                   autoresume,
+
        /* queue commands only, only one command per LUN */
        .can_queue =                    1,
        .cmd_per_lun =                  1,


-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to