X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fstorage%2Fusb.c;h=0a8c42a0a8bf24a6b5c0003933314bd23e3e7609;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=9579bdf4969abbfa9c09f29b29235c8565ea0ee4;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 9579bdf49..0a8c42a0a 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,11 @@ MODULE_AUTHOR("Matthew Dharm "); MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); MODULE_LICENSE("GPL"); +static unsigned int delay_use = 5; +module_param(delay_use, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); + + static int storage_probe(struct usb_interface *iface, const struct usb_device_id *id); @@ -257,16 +263,17 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data, available from the device."). */ memset(data+8,0,28); } else { + u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice); memcpy(data+8, us->unusual_dev->vendorName, strlen(us->unusual_dev->vendorName) > 8 ? 8 : strlen(us->unusual_dev->vendorName)); memcpy(data+16, us->unusual_dev->productName, strlen(us->unusual_dev->productName) > 16 ? 16 : strlen(us->unusual_dev->productName)); - data[32] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>12) & 0x0F); - data[33] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>8) & 0x0F); - data[34] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice>>4) & 0x0F); - data[35] = 0x30 + ((us->pusb_dev->descriptor.bcdDevice) & 0x0F); + data[32] = 0x30 + ((bcdDevice>>12) & 0x0F); + data[33] = 0x30 + ((bcdDevice>>8) & 0x0F); + data[34] = 0x30 + ((bcdDevice>>4) & 0x0F); + data[35] = 0x30 + ((bcdDevice) & 0x0F); } usb_stor_set_xfer_buf(data, data_len, us->srb); @@ -312,8 +319,8 @@ static int usb_stor_control_thread(void * __us) /* lock access to the state */ scsi_lock(host); - /* has the command been aborted *already* ? */ - if (us->sm_state == US_STATE_ABORTING) { + /* has the command timed out *already* ? */ + if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) { us->srb->result = DID_ABORT << 16; goto SkipForAbort; } @@ -324,8 +331,6 @@ static int usb_stor_control_thread(void * __us) goto SkipForDisconnect; } - /* set the state and release the lock */ - us->sm_state = US_STATE_RUNNING; scsi_unlock(host); /* reject the command if the direction indicator @@ -386,16 +391,15 @@ SkipForAbort: /* If an abort request was received we need to signal that * the abort has finished. The proper test for this is - * sm_state == US_STATE_ABORTING, not srb->result == DID_ABORT, - * because an abort request might be received after all the + * the TIMED_OUT flag, not srb->result == DID_ABORT, because + * a timeout/abort request might be received after all the * USB processing was complete. */ - if (us->sm_state == US_STATE_ABORTING) + if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) complete(&(us->notify)); - /* empty the queue, reset the state, and release the lock */ + /* finished working on this command */ SkipForDisconnect: us->srb = NULL; - us->sm_state = US_STATE_IDLE; scsi_unlock(host); /* unlock the device pointers */ @@ -433,9 +437,9 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf) us->pusb_intf = intf; us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", - us->pusb_dev->descriptor.idVendor, - us->pusb_dev->descriptor.idProduct, - us->pusb_dev->descriptor.bcdDevice); + le16_to_cpu(us->pusb_dev->descriptor.idVendor), + le16_to_cpu(us->pusb_dev->descriptor.idProduct), + le16_to_cpu(us->pusb_dev->descriptor.bcdDevice)); US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", intf->cur_altsetting->desc.bInterfaceSubClass, intf->cur_altsetting->desc.bInterfaceProtocol); @@ -504,8 +508,9 @@ static void get_device_info(struct us_data *us, int id_index) " has %s in unusual_devs.h\n" " Please send a copy of this message to " "\n", - ddesc->idVendor, ddesc->idProduct, - ddesc->bcdDevice, + le16_to_cpu(ddesc->idVendor), + le16_to_cpu(ddesc->idProduct), + le16_to_cpu(ddesc->bcdDevice), idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, msgs[msg]); @@ -795,7 +800,6 @@ static int usb_stor_acquire_resources(struct us_data *us) us->host->hostdata[0] = (unsigned long) us; /* Start up our control thread */ - us->sm_state = US_STATE_IDLE; p = kernel_thread(usb_stor_control_thread, us, CLONE_VM); if (p < 0) { printk(KERN_WARNING USB_STORAGE @@ -823,7 +827,6 @@ void usb_stor_release_resources(struct us_data *us) /* Wait for the thread to be idle */ down(&us->dev_semaphore); US_DEBUGP("-- sending exit command to thread\n"); - BUG_ON(us->sm_state != US_STATE_IDLE); /* If the SCSI midlayer queued a final command just before * scsi_remove_host() was called, us->srb might not be @@ -882,6 +885,46 @@ static void dissociate_dev(struct us_data *us) kfree(us); } +/* Thread to carry out delayed SCSI-device scanning */ +static int usb_stor_scan_thread(void * __us) +{ + struct us_data *us = (struct us_data *)__us; + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources. + */ + lock_kernel(); + daemonize("usb-stor-scan"); + unlock_kernel(); + + printk(KERN_DEBUG + "usb-storage: device found at %d\n", us->pusb_dev->devnum); + + /* Wait for the timeout to expire or for a disconnect */ + if (delay_use > 0) { + printk(KERN_DEBUG "usb-storage: waiting for device " + "to settle before scanning\n"); +retry: + wait_event_interruptible_timeout(us->scsi_scan_wait, + test_bit(US_FLIDX_DISCONNECTING, &us->flags), + delay_use * HZ); + if (current->flags & PF_FREEZE) { + refrigerator(PF_FREEZE); + goto retry; + } + } + + /* If the device is still connected, perform the scanning */ + if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { + scsi_scan_host(us->host); + printk(KERN_DEBUG "usb-storage: device scan complete\n"); + } + + complete_and_exit(&us->scsi_scan_done, 0); +} + + /* Probe to see if we can drive a newly-connected USB device */ static int storage_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -903,6 +946,8 @@ static int storage_probe(struct usb_interface *intf, init_MUTEX_LOCKED(&(us->sema)); init_completion(&(us->notify)); init_waitqueue_head(&us->dev_reset_wait); + init_waitqueue_head(&us->scsi_scan_wait); + init_completion(&us->scsi_scan_done); /* Associate the us_data structure with the USB device */ result = associate_dev(us, intf); @@ -951,12 +996,10 @@ static int storage_probe(struct usb_interface *intf, if (result) goto BadDevice; - /* Acquire all the other resources */ + /* Acquire all the other resources and add the host */ result = usb_stor_acquire_resources(us); if (result) goto BadDevice; - - /* Finally, add the host (this does SCSI device scanning) */ result = scsi_add_host(us->host, &intf->dev); if (result) { printk(KERN_WARNING USB_STORAGE @@ -964,10 +1007,15 @@ static int storage_probe(struct usb_interface *intf, goto BadDevice; } - scsi_scan_host(us->host); + /* Start up the thread for delayed SCSI-device scanning */ + result = kernel_thread(usb_stor_scan_thread, us, CLONE_VM); + if (result < 0) { + printk(KERN_WARNING USB_STORAGE + "Unable to start the device-scanning thread\n"); + scsi_remove_host(us->host); + goto BadDevice; + } - printk(KERN_DEBUG - "USB Mass Storage device found at %d\n", us->pusb_dev->devnum); return 0; /* We come here if there are any problems */ @@ -991,6 +1039,11 @@ static void storage_disconnect(struct usb_interface *intf) usb_stor_stop_transport(us); wake_up(&us->dev_reset_wait); + /* Interrupt the SCSI-device-scanning thread's time delay, and + * wait for the thread to finish */ + wake_up(&us->scsi_scan_wait); + wait_for_completion(&us->scsi_scan_done); + /* Wait for the current command to finish, then remove the host */ down(&us->dev_semaphore); up(&us->dev_semaphore); @@ -1012,12 +1065,9 @@ static int __init usb_stor_init(void) /* register the driver, return usb_register return code if error */ retval = usb_register(&usb_storage_driver); - if (retval) - goto out; + if (retval == 0) + printk(KERN_INFO "USB Mass Storage support registered.\n"); - /* we're all set */ - printk(KERN_INFO "USB Mass Storage support registered.\n"); -out: return retval; }