diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2007-07-06 14:24:27 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:34:43 -0400 |
commit | 8dfe4b14869fd185ca25ee88b02ada58a3005eaf (patch) | |
tree | 0c0c8812f1d038706bd82ff0d7b3570d67645e68 /drivers/usb/storage/usb.c | |
parent | b0e2a705bffbfb70d9bed8b5f9094901f28d9563 (diff) |
usb-storage: implement autosuspend
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 <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index cf3fc91234e7..bef8bcd9bd98 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -191,16 +191,14 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message) | |||
191 | { | 191 | { |
192 | struct us_data *us = usb_get_intfdata(iface); | 192 | struct us_data *us = usb_get_intfdata(iface); |
193 | 193 | ||
194 | US_DEBUGP("%s\n", __FUNCTION__); | ||
195 | |||
194 | /* Wait until no command is running */ | 196 | /* Wait until no command is running */ |
195 | mutex_lock(&us->dev_mutex); | 197 | mutex_lock(&us->dev_mutex); |
196 | 198 | ||
197 | US_DEBUGP("%s\n", __FUNCTION__); | ||
198 | if (us->suspend_resume_hook) | 199 | if (us->suspend_resume_hook) |
199 | (us->suspend_resume_hook)(us, US_SUSPEND); | 200 | (us->suspend_resume_hook)(us, US_SUSPEND); |
200 | 201 | ||
201 | /* When runtime PM is working, we'll set a flag to indicate | ||
202 | * whether we should autoresume when a SCSI request arrives. */ | ||
203 | |||
204 | mutex_unlock(&us->dev_mutex); | 202 | mutex_unlock(&us->dev_mutex); |
205 | return 0; | 203 | return 0; |
206 | } | 204 | } |
@@ -209,13 +207,11 @@ static int storage_resume(struct usb_interface *iface) | |||
209 | { | 207 | { |
210 | struct us_data *us = usb_get_intfdata(iface); | 208 | struct us_data *us = usb_get_intfdata(iface); |
211 | 209 | ||
212 | mutex_lock(&us->dev_mutex); | ||
213 | |||
214 | US_DEBUGP("%s\n", __FUNCTION__); | 210 | US_DEBUGP("%s\n", __FUNCTION__); |
211 | |||
215 | if (us->suspend_resume_hook) | 212 | if (us->suspend_resume_hook) |
216 | (us->suspend_resume_hook)(us, US_RESUME); | 213 | (us->suspend_resume_hook)(us, US_RESUME); |
217 | 214 | ||
218 | mutex_unlock(&us->dev_mutex); | ||
219 | return 0; | 215 | return 0; |
220 | } | 216 | } |
221 | 217 | ||
@@ -313,6 +309,7 @@ static int usb_stor_control_thread(void * __us) | |||
313 | { | 309 | { |
314 | struct us_data *us = (struct us_data *)__us; | 310 | struct us_data *us = (struct us_data *)__us; |
315 | struct Scsi_Host *host = us_to_host(us); | 311 | struct Scsi_Host *host = us_to_host(us); |
312 | int autopm_rc; | ||
316 | 313 | ||
317 | current->flags |= PF_NOFREEZE; | 314 | current->flags |= PF_NOFREEZE; |
318 | 315 | ||
@@ -323,6 +320,9 @@ static int usb_stor_control_thread(void * __us) | |||
323 | 320 | ||
324 | US_DEBUGP("*** thread awakened.\n"); | 321 | US_DEBUGP("*** thread awakened.\n"); |
325 | 322 | ||
323 | /* Autoresume the device */ | ||
324 | autopm_rc = usb_autopm_get_interface(us->pusb_intf); | ||
325 | |||
326 | /* lock the device pointers */ | 326 | /* lock the device pointers */ |
327 | mutex_lock(&(us->dev_mutex)); | 327 | mutex_lock(&(us->dev_mutex)); |
328 | 328 | ||
@@ -381,6 +381,12 @@ static int usb_stor_control_thread(void * __us) | |||
381 | us->srb->result = SAM_STAT_GOOD; | 381 | us->srb->result = SAM_STAT_GOOD; |
382 | } | 382 | } |
383 | 383 | ||
384 | /* Did the autoresume fail? */ | ||
385 | else if (autopm_rc < 0) { | ||
386 | US_DEBUGP("Could not wake device\n"); | ||
387 | us->srb->result = DID_ERROR << 16; | ||
388 | } | ||
389 | |||
384 | /* we've got a command, let's do it! */ | 390 | /* we've got a command, let's do it! */ |
385 | else { | 391 | else { |
386 | US_DEBUG(usb_stor_show_command(us->srb)); | 392 | US_DEBUG(usb_stor_show_command(us->srb)); |
@@ -423,6 +429,10 @@ SkipForAbort: | |||
423 | 429 | ||
424 | /* unlock the device pointers */ | 430 | /* unlock the device pointers */ |
425 | mutex_unlock(&us->dev_mutex); | 431 | mutex_unlock(&us->dev_mutex); |
432 | |||
433 | /* Start an autosuspend */ | ||
434 | if (autopm_rc == 0) | ||
435 | usb_autopm_put_interface(us->pusb_intf); | ||
426 | } /* for (;;) */ | 436 | } /* for (;;) */ |
427 | 437 | ||
428 | /* Wait until we are told to stop */ | 438 | /* Wait until we are told to stop */ |
@@ -939,6 +949,7 @@ retry: | |||
939 | } | 949 | } |
940 | 950 | ||
941 | scsi_host_put(us_to_host(us)); | 951 | scsi_host_put(us_to_host(us)); |
952 | usb_autopm_put_interface(us->pusb_intf); | ||
942 | complete_and_exit(&threads_gone, 0); | 953 | complete_and_exit(&threads_gone, 0); |
943 | } | 954 | } |
944 | 955 | ||
@@ -1028,6 +1039,7 @@ static int storage_probe(struct usb_interface *intf, | |||
1028 | * start it up. */ | 1039 | * start it up. */ |
1029 | scsi_host_get(us_to_host(us)); | 1040 | scsi_host_get(us_to_host(us)); |
1030 | atomic_inc(&total_threads); | 1041 | atomic_inc(&total_threads); |
1042 | usb_autopm_get_interface(intf); /* dropped in the scanning thread */ | ||
1031 | wake_up_process(th); | 1043 | wake_up_process(th); |
1032 | 1044 | ||
1033 | return 0; | 1045 | return 0; |
@@ -1065,6 +1077,7 @@ static struct usb_driver usb_storage_driver = { | |||
1065 | .pre_reset = storage_pre_reset, | 1077 | .pre_reset = storage_pre_reset, |
1066 | .post_reset = storage_post_reset, | 1078 | .post_reset = storage_post_reset, |
1067 | .id_table = storage_usb_ids, | 1079 | .id_table = storage_usb_ids, |
1080 | .supports_autosuspend = 1, | ||
1068 | }; | 1081 | }; |
1069 | 1082 | ||
1070 | static int __init usb_stor_init(void) | 1083 | static int __init usb_stor_init(void) |