diff options
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 91 |
1 files changed, 53 insertions, 38 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 8e898e3d861e..bef8bcd9bd98 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -191,16 +191,13 @@ 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 | iface->dev.power.power_state.event = message.event; | ||
201 | |||
202 | /* When runtime PM is working, we'll set a flag to indicate | ||
203 | * whether we should autoresume when a SCSI request arrives. */ | ||
204 | 201 | ||
205 | mutex_unlock(&us->dev_mutex); | 202 | mutex_unlock(&us->dev_mutex); |
206 | return 0; | 203 | return 0; |
@@ -210,14 +207,25 @@ static int storage_resume(struct usb_interface *iface) | |||
210 | { | 207 | { |
211 | struct us_data *us = usb_get_intfdata(iface); | 208 | struct us_data *us = usb_get_intfdata(iface); |
212 | 209 | ||
213 | mutex_lock(&us->dev_mutex); | ||
214 | |||
215 | US_DEBUGP("%s\n", __FUNCTION__); | 210 | US_DEBUGP("%s\n", __FUNCTION__); |
211 | |||
216 | if (us->suspend_resume_hook) | 212 | if (us->suspend_resume_hook) |
217 | (us->suspend_resume_hook)(us, US_RESUME); | 213 | (us->suspend_resume_hook)(us, US_RESUME); |
218 | iface->dev.power.power_state.event = PM_EVENT_ON; | ||
219 | 214 | ||
220 | mutex_unlock(&us->dev_mutex); | 215 | return 0; |
216 | } | ||
217 | |||
218 | static int storage_reset_resume(struct usb_interface *iface) | ||
219 | { | ||
220 | struct us_data *us = usb_get_intfdata(iface); | ||
221 | |||
222 | US_DEBUGP("%s\n", __FUNCTION__); | ||
223 | |||
224 | /* Report the reset to the SCSI core */ | ||
225 | usb_stor_report_bus_reset(us); | ||
226 | |||
227 | /* FIXME: Notify the subdrivers that they need to reinitialize | ||
228 | * the device */ | ||
221 | return 0; | 229 | return 0; |
222 | } | 230 | } |
223 | 231 | ||
@@ -228,7 +236,7 @@ static int storage_resume(struct usb_interface *iface) | |||
228 | * a USB port reset, whether from this driver or a different one. | 236 | * a USB port reset, whether from this driver or a different one. |
229 | */ | 237 | */ |
230 | 238 | ||
231 | static void storage_pre_reset(struct usb_interface *iface) | 239 | static int storage_pre_reset(struct usb_interface *iface) |
232 | { | 240 | { |
233 | struct us_data *us = usb_get_intfdata(iface); | 241 | struct us_data *us = usb_get_intfdata(iface); |
234 | 242 | ||
@@ -236,22 +244,23 @@ static void storage_pre_reset(struct usb_interface *iface) | |||
236 | 244 | ||
237 | /* Make sure no command runs during the reset */ | 245 | /* Make sure no command runs during the reset */ |
238 | mutex_lock(&us->dev_mutex); | 246 | mutex_lock(&us->dev_mutex); |
247 | return 0; | ||
239 | } | 248 | } |
240 | 249 | ||
241 | static void storage_post_reset(struct usb_interface *iface) | 250 | static int storage_post_reset(struct usb_interface *iface) |
242 | { | 251 | { |
243 | struct us_data *us = usb_get_intfdata(iface); | 252 | struct us_data *us = usb_get_intfdata(iface); |
244 | 253 | ||
245 | US_DEBUGP("%s\n", __FUNCTION__); | 254 | US_DEBUGP("%s\n", __FUNCTION__); |
246 | 255 | ||
247 | /* Report the reset to the SCSI core */ | 256 | /* Report the reset to the SCSI core */ |
248 | scsi_lock(us_to_host(us)); | ||
249 | usb_stor_report_bus_reset(us); | 257 | usb_stor_report_bus_reset(us); |
250 | scsi_unlock(us_to_host(us)); | ||
251 | 258 | ||
252 | /* FIXME: Notify the subdrivers that they need to reinitialize | 259 | /* FIXME: Notify the subdrivers that they need to reinitialize |
253 | * the device */ | 260 | * the device */ |
261 | |||
254 | mutex_unlock(&us->dev_mutex); | 262 | mutex_unlock(&us->dev_mutex); |
263 | return 0; | ||
255 | } | 264 | } |
256 | 265 | ||
257 | /* | 266 | /* |
@@ -300,6 +309,7 @@ static int usb_stor_control_thread(void * __us) | |||
300 | { | 309 | { |
301 | struct us_data *us = (struct us_data *)__us; | 310 | struct us_data *us = (struct us_data *)__us; |
302 | struct Scsi_Host *host = us_to_host(us); | 311 | struct Scsi_Host *host = us_to_host(us); |
312 | int autopm_rc; | ||
303 | 313 | ||
304 | current->flags |= PF_NOFREEZE; | 314 | current->flags |= PF_NOFREEZE; |
305 | 315 | ||
@@ -310,6 +320,9 @@ static int usb_stor_control_thread(void * __us) | |||
310 | 320 | ||
311 | US_DEBUGP("*** thread awakened.\n"); | 321 | US_DEBUGP("*** thread awakened.\n"); |
312 | 322 | ||
323 | /* Autoresume the device */ | ||
324 | autopm_rc = usb_autopm_get_interface(us->pusb_intf); | ||
325 | |||
313 | /* lock the device pointers */ | 326 | /* lock the device pointers */ |
314 | mutex_lock(&(us->dev_mutex)); | 327 | mutex_lock(&(us->dev_mutex)); |
315 | 328 | ||
@@ -368,6 +381,12 @@ static int usb_stor_control_thread(void * __us) | |||
368 | us->srb->result = SAM_STAT_GOOD; | 381 | us->srb->result = SAM_STAT_GOOD; |
369 | } | 382 | } |
370 | 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 | |||
371 | /* we've got a command, let's do it! */ | 390 | /* we've got a command, let's do it! */ |
372 | else { | 391 | else { |
373 | US_DEBUG(usb_stor_show_command(us->srb)); | 392 | US_DEBUG(usb_stor_show_command(us->srb)); |
@@ -410,25 +429,21 @@ SkipForAbort: | |||
410 | 429 | ||
411 | /* unlock the device pointers */ | 430 | /* unlock the device pointers */ |
412 | mutex_unlock(&us->dev_mutex); | 431 | mutex_unlock(&us->dev_mutex); |
413 | } /* for (;;) */ | ||
414 | 432 | ||
415 | scsi_host_put(host); | 433 | /* Start an autosuspend */ |
434 | if (autopm_rc == 0) | ||
435 | usb_autopm_put_interface(us->pusb_intf); | ||
436 | } /* for (;;) */ | ||
416 | 437 | ||
417 | /* notify the exit routine that we're actually exiting now | 438 | /* Wait until we are told to stop */ |
418 | * | 439 | for (;;) { |
419 | * complete()/wait_for_completion() is similar to up()/down(), | 440 | set_current_state(TASK_INTERRUPTIBLE); |
420 | * except that complete() is safe in the case where the structure | 441 | if (kthread_should_stop()) |
421 | * is getting deleted in a parallel mode of execution (i.e. just | 442 | break; |
422 | * after the down() -- that's necessary for the thread-shutdown | 443 | schedule(); |
423 | * case. | 444 | } |
424 | * | 445 | __set_current_state(TASK_RUNNING); |
425 | * complete_and_exit() goes even further than this -- it is safe in | 446 | return 0; |
426 | * the case that the thread of the caller is going away (not just | ||
427 | * the structure) -- this is necessary for the module-remove case. | ||
428 | * This is important in preemption kernels, which transfer the flow | ||
429 | * of execution immediately upon a complete(). | ||
430 | */ | ||
431 | complete_and_exit(&threads_gone, 0); | ||
432 | } | 447 | } |
433 | 448 | ||
434 | /*********************************************************************** | 449 | /*********************************************************************** |
@@ -796,19 +811,13 @@ static int usb_stor_acquire_resources(struct us_data *us) | |||
796 | } | 811 | } |
797 | 812 | ||
798 | /* Start up our control thread */ | 813 | /* Start up our control thread */ |
799 | th = kthread_create(usb_stor_control_thread, us, "usb-storage"); | 814 | th = kthread_run(usb_stor_control_thread, us, "usb-storage"); |
800 | if (IS_ERR(th)) { | 815 | if (IS_ERR(th)) { |
801 | printk(KERN_WARNING USB_STORAGE | 816 | printk(KERN_WARNING USB_STORAGE |
802 | "Unable to start control thread\n"); | 817 | "Unable to start control thread\n"); |
803 | return PTR_ERR(th); | 818 | return PTR_ERR(th); |
804 | } | 819 | } |
805 | 820 | us->ctl_thread = th; | |
806 | /* Take a reference to the host for the control thread and | ||
807 | * count it among all the threads we have launched. Then | ||
808 | * start it up. */ | ||
809 | scsi_host_get(us_to_host(us)); | ||
810 | atomic_inc(&total_threads); | ||
811 | wake_up_process(th); | ||
812 | 821 | ||
813 | return 0; | 822 | return 0; |
814 | } | 823 | } |
@@ -825,6 +834,8 @@ static void usb_stor_release_resources(struct us_data *us) | |||
825 | US_DEBUGP("-- sending exit command to thread\n"); | 834 | US_DEBUGP("-- sending exit command to thread\n"); |
826 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); | 835 | set_bit(US_FLIDX_DISCONNECTING, &us->flags); |
827 | up(&us->sema); | 836 | up(&us->sema); |
837 | if (us->ctl_thread) | ||
838 | kthread_stop(us->ctl_thread); | ||
828 | 839 | ||
829 | /* Call the destructor routine, if it exists */ | 840 | /* Call the destructor routine, if it exists */ |
830 | if (us->extra_destructor) { | 841 | if (us->extra_destructor) { |
@@ -938,6 +949,7 @@ retry: | |||
938 | } | 949 | } |
939 | 950 | ||
940 | scsi_host_put(us_to_host(us)); | 951 | scsi_host_put(us_to_host(us)); |
952 | usb_autopm_put_interface(us->pusb_intf); | ||
941 | complete_and_exit(&threads_gone, 0); | 953 | complete_and_exit(&threads_gone, 0); |
942 | } | 954 | } |
943 | 955 | ||
@@ -1027,6 +1039,7 @@ static int storage_probe(struct usb_interface *intf, | |||
1027 | * start it up. */ | 1039 | * start it up. */ |
1028 | scsi_host_get(us_to_host(us)); | 1040 | scsi_host_get(us_to_host(us)); |
1029 | atomic_inc(&total_threads); | 1041 | atomic_inc(&total_threads); |
1042 | usb_autopm_get_interface(intf); /* dropped in the scanning thread */ | ||
1030 | wake_up_process(th); | 1043 | wake_up_process(th); |
1031 | 1044 | ||
1032 | return 0; | 1045 | return 0; |
@@ -1059,10 +1072,12 @@ static struct usb_driver usb_storage_driver = { | |||
1059 | #ifdef CONFIG_PM | 1072 | #ifdef CONFIG_PM |
1060 | .suspend = storage_suspend, | 1073 | .suspend = storage_suspend, |
1061 | .resume = storage_resume, | 1074 | .resume = storage_resume, |
1075 | .reset_resume = storage_reset_resume, | ||
1062 | #endif | 1076 | #endif |
1063 | .pre_reset = storage_pre_reset, | 1077 | .pre_reset = storage_pre_reset, |
1064 | .post_reset = storage_post_reset, | 1078 | .post_reset = storage_post_reset, |
1065 | .id_table = storage_usb_ids, | 1079 | .id_table = storage_usb_ids, |
1080 | .supports_autosuspend = 1, | ||
1066 | }; | 1081 | }; |
1067 | 1082 | ||
1068 | static int __init usb_stor_init(void) | 1083 | static int __init usb_stor_init(void) |