#include <linux/config.h>
#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/suspend.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
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);
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);
/* 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;
}
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
/* 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 */
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);
" has %s in unusual_devs.h\n"
" Please send a copy of this message to "
"<linux-usb-devel@lists.sourceforge.net>\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]);
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
/* 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
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)
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);
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
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 */
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);
/* 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;
}