diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-29 00:08:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-29 00:08:14 -0400 |
commit | 1f419cadff55f548e7356ffebdb9e1b5a8c22275 (patch) | |
tree | 07c04d053322e9913a6b445b2fe00510299e97cf /drivers/usb/storage/usb.c | |
parent | 974f7bc5781d3fc16e32d8908c6e48592e767dd2 (diff) | |
parent | 4303fc6f055cf1a7ec63c3c3fd777b91b7d576f1 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 163 |
1 files changed, 90 insertions, 73 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index f9a9bfa1aef5..3847ebed2aa4 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #include <linux/module.h> | 54 | #include <linux/module.h> |
55 | #include <linux/init.h> | 55 | #include <linux/init.h> |
56 | #include <linux/slab.h> | 56 | #include <linux/slab.h> |
57 | #include <linux/kthread.h> | ||
57 | 58 | ||
58 | #include <scsi/scsi.h> | 59 | #include <scsi/scsi.h> |
59 | #include <scsi/scsi_cmnd.h> | 60 | #include <scsi/scsi_cmnd.h> |
@@ -111,11 +112,6 @@ static atomic_t total_threads = ATOMIC_INIT(0); | |||
111 | static DECLARE_COMPLETION(threads_gone); | 112 | static DECLARE_COMPLETION(threads_gone); |
112 | 113 | ||
113 | 114 | ||
114 | static int storage_probe(struct usb_interface *iface, | ||
115 | const struct usb_device_id *id); | ||
116 | |||
117 | static void storage_disconnect(struct usb_interface *iface); | ||
118 | |||
119 | /* The entries in this table, except for final ones here | 115 | /* The entries in this table, except for final ones here |
120 | * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, | 116 | * (USB_MASS_STORAGE_CLASS and the empty entry), correspond, |
121 | * line for line with the entries of us_unsuaul_dev_list[]. | 117 | * line for line with the entries of us_unsuaul_dev_list[]. |
@@ -233,13 +229,40 @@ static struct us_unusual_dev us_unusual_dev_list[] = { | |||
233 | { NULL } | 229 | { NULL } |
234 | }; | 230 | }; |
235 | 231 | ||
236 | static struct usb_driver usb_storage_driver = { | 232 | |
237 | .owner = THIS_MODULE, | 233 | #ifdef CONFIG_PM /* Minimal support for suspend and resume */ |
238 | .name = "usb-storage", | 234 | |
239 | .probe = storage_probe, | 235 | static int storage_suspend(struct usb_interface *iface, pm_message_t message) |
240 | .disconnect = storage_disconnect, | 236 | { |
241 | .id_table = storage_usb_ids, | 237 | struct us_data *us = usb_get_intfdata(iface); |
242 | }; | 238 | |
239 | /* Wait until no command is running */ | ||
240 | down(&us->dev_semaphore); | ||
241 | |||
242 | US_DEBUGP("%s\n", __FUNCTION__); | ||
243 | iface->dev.power.power_state.event = message.event; | ||
244 | |||
245 | /* When runtime PM is working, we'll set a flag to indicate | ||
246 | * whether we should autoresume when a SCSI request arrives. */ | ||
247 | |||
248 | up(&us->dev_semaphore); | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int storage_resume(struct usb_interface *iface) | ||
253 | { | ||
254 | struct us_data *us = usb_get_intfdata(iface); | ||
255 | |||
256 | down(&us->dev_semaphore); | ||
257 | |||
258 | US_DEBUGP("%s\n", __FUNCTION__); | ||
259 | iface->dev.power.power_state.event = PM_EVENT_ON; | ||
260 | |||
261 | up(&us->dev_semaphore); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | #endif /* CONFIG_PM */ | ||
243 | 266 | ||
244 | /* | 267 | /* |
245 | * fill_inquiry_response takes an unsigned char array (which must | 268 | * fill_inquiry_response takes an unsigned char array (which must |
@@ -288,22 +311,7 @@ static int usb_stor_control_thread(void * __us) | |||
288 | struct us_data *us = (struct us_data *)__us; | 311 | struct us_data *us = (struct us_data *)__us; |
289 | struct Scsi_Host *host = us_to_host(us); | 312 | struct Scsi_Host *host = us_to_host(us); |
290 | 313 | ||
291 | lock_kernel(); | ||
292 | |||
293 | /* | ||
294 | * This thread doesn't need any user-level access, | ||
295 | * so get rid of all our resources. | ||
296 | */ | ||
297 | daemonize("usb-storage"); | ||
298 | current->flags |= PF_NOFREEZE; | 314 | current->flags |= PF_NOFREEZE; |
299 | unlock_kernel(); | ||
300 | |||
301 | /* acquire a reference to the host, so it won't be deallocated | ||
302 | * until we're ready to exit */ | ||
303 | scsi_host_get(host); | ||
304 | |||
305 | /* signal that we've started the thread */ | ||
306 | complete(&(us->notify)); | ||
307 | 315 | ||
308 | for(;;) { | 316 | for(;;) { |
309 | US_DEBUGP("*** thread sleeping.\n"); | 317 | US_DEBUGP("*** thread sleeping.\n"); |
@@ -467,6 +475,12 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) | |||
467 | US_DEBUGP("I/O buffer allocation failed\n"); | 475 | US_DEBUGP("I/O buffer allocation failed\n"); |
468 | return -ENOMEM; | 476 | return -ENOMEM; |
469 | } | 477 | } |
478 | |||
479 | us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL); | ||
480 | if (!us->sensebuf) { | ||
481 | US_DEBUGP("Sense buffer allocation failed\n"); | ||
482 | return -ENOMEM; | ||
483 | } | ||
470 | return 0; | 484 | return 0; |
471 | } | 485 | } |
472 | 486 | ||
@@ -555,8 +569,8 @@ static int get_transport(struct us_data *us) | |||
555 | break; | 569 | break; |
556 | 570 | ||
557 | #ifdef CONFIG_USB_STORAGE_USBAT | 571 | #ifdef CONFIG_USB_STORAGE_USBAT |
558 | case US_PR_SCM_ATAPI: | 572 | case US_PR_USBAT: |
559 | us->transport_name = "SCM/ATAPI"; | 573 | us->transport_name = "Shuttle USBAT"; |
560 | us->transport = usbat_transport; | 574 | us->transport = usbat_transport; |
561 | us->transport_reset = usb_stor_CB_reset; | 575 | us->transport_reset = usb_stor_CB_reset; |
562 | us->max_lun = 1; | 576 | us->max_lun = 1; |
@@ -740,6 +754,7 @@ static int get_pipes(struct us_data *us) | |||
740 | static int usb_stor_acquire_resources(struct us_data *us) | 754 | static int usb_stor_acquire_resources(struct us_data *us) |
741 | { | 755 | { |
742 | int p; | 756 | int p; |
757 | struct task_struct *th; | ||
743 | 758 | ||
744 | us->current_urb = usb_alloc_urb(0, GFP_KERNEL); | 759 | us->current_urb = usb_alloc_urb(0, GFP_KERNEL); |
745 | if (!us->current_urb) { | 760 | if (!us->current_urb) { |
@@ -747,38 +762,28 @@ static int usb_stor_acquire_resources(struct us_data *us) | |||
747 | return -ENOMEM; | 762 | return -ENOMEM; |
748 | } | 763 | } |
749 | 764 | ||
750 | /* Lock the device while we carry out the next two operations */ | ||
751 | down(&us->dev_semaphore); | ||
752 | |||
753 | /* For bulk-only devices, determine the max LUN value */ | ||
754 | if (us->protocol == US_PR_BULK) { | ||
755 | p = usb_stor_Bulk_max_lun(us); | ||
756 | if (p < 0) { | ||
757 | up(&us->dev_semaphore); | ||
758 | return p; | ||
759 | } | ||
760 | us->max_lun = p; | ||
761 | } | ||
762 | |||
763 | /* Just before we start our control thread, initialize | 765 | /* Just before we start our control thread, initialize |
764 | * the device if it needs initialization */ | 766 | * the device if it needs initialization */ |
765 | if (us->unusual_dev->initFunction) | 767 | if (us->unusual_dev->initFunction) { |
766 | us->unusual_dev->initFunction(us); | 768 | p = us->unusual_dev->initFunction(us); |
767 | 769 | if (p) | |
768 | up(&us->dev_semaphore); | 770 | return p; |
771 | } | ||
769 | 772 | ||
770 | /* Start up our control thread */ | 773 | /* Start up our control thread */ |
771 | p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); | 774 | th = kthread_create(usb_stor_control_thread, us, "usb-storage"); |
772 | if (p < 0) { | 775 | if (IS_ERR(th)) { |
773 | printk(KERN_WARNING USB_STORAGE | 776 | printk(KERN_WARNING USB_STORAGE |
774 | "Unable to start control thread\n"); | 777 | "Unable to start control thread\n"); |
775 | return p; | 778 | return PTR_ERR(th); |
776 | } | 779 | } |
777 | us->pid = p; | ||
778 | atomic_inc(&total_threads); | ||
779 | 780 | ||
780 | /* Wait for the thread to start */ | 781 | /* Take a reference to the host for the control thread and |
781 | wait_for_completion(&(us->notify)); | 782 | * count it among all the threads we have launched. Then |
783 | * start it up. */ | ||
784 | scsi_host_get(us_to_host(us)); | ||
785 | atomic_inc(&total_threads); | ||
786 | wake_up_process(th); | ||
782 | 787 | ||
783 | return 0; | 788 | return 0; |
784 | } | 789 | } |
@@ -812,6 +817,8 @@ static void dissociate_dev(struct us_data *us) | |||
812 | { | 817 | { |
813 | US_DEBUGP("-- %s\n", __FUNCTION__); | 818 | US_DEBUGP("-- %s\n", __FUNCTION__); |
814 | 819 | ||
820 | kfree(us->sensebuf); | ||
821 | |||
815 | /* Free the device-related DMA-mapped buffers */ | 822 | /* Free the device-related DMA-mapped buffers */ |
816 | if (us->cr) | 823 | if (us->cr) |
817 | usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr, | 824 | usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr, |
@@ -872,21 +879,6 @@ static int usb_stor_scan_thread(void * __us) | |||
872 | { | 879 | { |
873 | struct us_data *us = (struct us_data *)__us; | 880 | struct us_data *us = (struct us_data *)__us; |
874 | 881 | ||
875 | /* | ||
876 | * This thread doesn't need any user-level access, | ||
877 | * so get rid of all our resources. | ||
878 | */ | ||
879 | lock_kernel(); | ||
880 | daemonize("usb-stor-scan"); | ||
881 | unlock_kernel(); | ||
882 | |||
883 | /* Acquire a reference to the host, so it won't be deallocated | ||
884 | * until we're ready to exit */ | ||
885 | scsi_host_get(us_to_host(us)); | ||
886 | |||
887 | /* Signal that we've started the thread */ | ||
888 | complete(&(us->notify)); | ||
889 | |||
890 | printk(KERN_DEBUG | 882 | printk(KERN_DEBUG |
891 | "usb-storage: device found at %d\n", us->pusb_dev->devnum); | 883 | "usb-storage: device found at %d\n", us->pusb_dev->devnum); |
892 | 884 | ||
@@ -904,6 +896,14 @@ retry: | |||
904 | 896 | ||
905 | /* If the device is still connected, perform the scanning */ | 897 | /* If the device is still connected, perform the scanning */ |
906 | if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { | 898 | if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { |
899 | |||
900 | /* For bulk-only devices, determine the max LUN value */ | ||
901 | if (us->protocol == US_PR_BULK && | ||
902 | !(us->flags & US_FL_SINGLE_LUN)) { | ||
903 | down(&us->dev_semaphore); | ||
904 | us->max_lun = usb_stor_Bulk_max_lun(us); | ||
905 | up(&us->dev_semaphore); | ||
906 | } | ||
907 | scsi_scan_host(us_to_host(us)); | 907 | scsi_scan_host(us_to_host(us)); |
908 | printk(KERN_DEBUG "usb-storage: device scan complete\n"); | 908 | printk(KERN_DEBUG "usb-storage: device scan complete\n"); |
909 | 909 | ||
@@ -923,6 +923,7 @@ static int storage_probe(struct usb_interface *intf, | |||
923 | struct us_data *us; | 923 | struct us_data *us; |
924 | const int id_index = id - storage_usb_ids; | 924 | const int id_index = id - storage_usb_ids; |
925 | int result; | 925 | int result; |
926 | struct task_struct *th; | ||
926 | 927 | ||
927 | US_DEBUGP("USB Mass Storage device detected\n"); | 928 | US_DEBUGP("USB Mass Storage device detected\n"); |
928 | 929 | ||
@@ -1003,17 +1004,21 @@ static int storage_probe(struct usb_interface *intf, | |||
1003 | } | 1004 | } |
1004 | 1005 | ||
1005 | /* Start up the thread for delayed SCSI-device scanning */ | 1006 | /* Start up the thread for delayed SCSI-device scanning */ |
1006 | result = kernel_thread(usb_stor_scan_thread, us, CLONE_VM); | 1007 | th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); |
1007 | if (result < 0) { | 1008 | if (IS_ERR(th)) { |
1008 | printk(KERN_WARNING USB_STORAGE | 1009 | printk(KERN_WARNING USB_STORAGE |
1009 | "Unable to start the device-scanning thread\n"); | 1010 | "Unable to start the device-scanning thread\n"); |
1010 | quiesce_and_remove_host(us); | 1011 | quiesce_and_remove_host(us); |
1012 | result = PTR_ERR(th); | ||
1011 | goto BadDevice; | 1013 | goto BadDevice; |
1012 | } | 1014 | } |
1013 | atomic_inc(&total_threads); | ||
1014 | 1015 | ||
1015 | /* Wait for the thread to start */ | 1016 | /* Take a reference to the host for the scanning thread and |
1016 | wait_for_completion(&(us->notify)); | 1017 | * count it among all the threads we have launched. Then |
1018 | * start it up. */ | ||
1019 | scsi_host_get(us_to_host(us)); | ||
1020 | atomic_inc(&total_threads); | ||
1021 | wake_up_process(th); | ||
1017 | 1022 | ||
1018 | return 0; | 1023 | return 0; |
1019 | 1024 | ||
@@ -1038,6 +1043,18 @@ static void storage_disconnect(struct usb_interface *intf) | |||
1038 | * Initialization and registration | 1043 | * Initialization and registration |
1039 | ***********************************************************************/ | 1044 | ***********************************************************************/ |
1040 | 1045 | ||
1046 | static struct usb_driver usb_storage_driver = { | ||
1047 | .owner = THIS_MODULE, | ||
1048 | .name = "usb-storage", | ||
1049 | .probe = storage_probe, | ||
1050 | .disconnect = storage_disconnect, | ||
1051 | #ifdef CONFIG_PM | ||
1052 | .suspend = storage_suspend, | ||
1053 | .resume = storage_resume, | ||
1054 | #endif | ||
1055 | .id_table = storage_usb_ids, | ||
1056 | }; | ||
1057 | |||
1041 | static int __init usb_stor_init(void) | 1058 | static int __init usb_stor_init(void) |
1042 | { | 1059 | { |
1043 | int retval; | 1060 | int retval; |