USB: usb-storage: add BAD_SENSE flag
[safe/jmp/linux-2.6] / drivers / usb / storage / usb.c
index 099e07c..f5c0264 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Developed with the assistance of:
  *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
- *   (c) 2003 Alan Stern (stern@rowland.harvard.edu)
+ *   (c) 2003-2009 Alan Stern (stern@rowland.harvard.edu)
  *
  * Initial work by:
  *   (c) 1999 Michael Gee (michael@linuxspecific.com)
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#ifdef CONFIG_USB_STORAGE_DEBUG
+#define DEBUG
+#endif
+
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/freezer.h>
 #include "debug.h"
 #include "initializers.h"
 
-#ifdef CONFIG_USB_STORAGE_USBAT
-#include "shuttle_usbat.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR09
-#include "sddr09.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_SDDR55
-#include "sddr55.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_DPCM
-#include "dpcm.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_FREECOM
-#include "freecom.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_ISD200
-#include "isd200.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-#include "datafab.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
-#include "jumpshot.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_ONETOUCH
-#include "onetouch.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_ALAUDA
-#include "alauda.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_KARMA
-#include "karma.h"
-#endif
-#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
-#include "cypress_atacb.h"
-#endif
 #include "sierra_ms.h"
+#include "option_ms.h"
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -113,46 +82,15 @@ 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 char *quirks;
-module_param(quirks, charp, S_IRUGO);
+static char quirks[128];
+module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
 
-struct quirks_entry {
-       u16     vid, pid;
-       u32     fflags;
-};
-static struct quirks_entry *quirks_list, *quirks_end;
-
 
 /*
  * The entries in this table correspond, line for line,
- * with the entries of us_unusual_dev_list[].
+ * with the entries in usb_storage_usb_ids[], defined in usual-tables.c.
  */
-#ifndef CONFIG_USB_LIBUSUAL
-
-#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
-                   vendorName, productName,useProtocol, useTransport, \
-                   initFunction, flags) \
-{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
-  .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
-
-#define USUAL_DEV(useProto, useTrans, useType) \
-{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
-  .driver_info = (USB_US_TYPE_STOR<<24) }
-
-static struct usb_device_id storage_usb_ids [] = {
-
-#      include "unusual_devs.h"
-#undef UNUSUAL_DEV
-#undef USUAL_DEV
-       /* Terminating entry */
-       { }
-};
-
-MODULE_DEVICE_TABLE (usb, storage_usb_ids);
-#endif /* CONFIG_USB_LIBUSUAL */
-
-/* This is the list of devices we recognize, along with their flag data */
 
 /* The vendor name should be kept at eight characters or less, and
  * the product name should be kept at 16 characters or less. If a device
@@ -174,6 +112,8 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
        .initFunction = init_function,  \
 }
 
+#define COMPLIANT_DEV  UNUSUAL_DEV
+
 #define USUAL_DEV(use_protocol, use_transport, use_type) \
 { \
        .useProtocol = use_protocol,    \
@@ -182,17 +122,17 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
 
 static struct us_unusual_dev us_unusual_dev_list[] = {
 #      include "unusual_devs.h" 
-#      undef UNUSUAL_DEV
-#      undef USUAL_DEV
-
-       /* Terminating entry */
-       { NULL }
+       { }             /* Terminating entry */
 };
 
+#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
+#undef USUAL_DEV
+
 
 #ifdef CONFIG_PM       /* Minimal support for suspend and resume */
 
-static int storage_suspend(struct usb_interface *iface, pm_message_t message)
+int usb_stor_suspend(struct usb_interface *iface, pm_message_t message)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
@@ -209,8 +149,9 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
        mutex_unlock(&us->dev_mutex);
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_stor_suspend);
 
-static int storage_resume(struct usb_interface *iface)
+int usb_stor_resume(struct usb_interface *iface)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
@@ -223,8 +164,9 @@ static int storage_resume(struct usb_interface *iface)
        mutex_unlock(&us->dev_mutex);
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_stor_resume);
 
-static int storage_reset_resume(struct usb_interface *iface)
+int usb_stor_reset_resume(struct usb_interface *iface)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
@@ -237,6 +179,7 @@ static int storage_reset_resume(struct usb_interface *iface)
         * the device */
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_stor_reset_resume);
 
 #endif /* CONFIG_PM */
 
@@ -245,7 +188,7 @@ static int storage_reset_resume(struct usb_interface *iface)
  * a USB port reset, whether from this driver or a different one.
  */
 
-static int storage_pre_reset(struct usb_interface *iface)
+int usb_stor_pre_reset(struct usb_interface *iface)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
@@ -255,8 +198,9 @@ static int storage_pre_reset(struct usb_interface *iface)
        mutex_lock(&us->dev_mutex);
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_stor_pre_reset);
 
-static int storage_post_reset(struct usb_interface *iface)
+int usb_stor_post_reset(struct usb_interface *iface)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
@@ -271,6 +215,7 @@ static int storage_post_reset(struct usb_interface *iface)
        mutex_unlock(&us->dev_mutex);
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_stor_post_reset);
 
 /*
  * fill_inquiry_response takes an unsigned char array (which must
@@ -313,6 +258,7 @@ void fill_inquiry_response(struct us_data *us, unsigned char *data,
 
        usb_stor_set_xfer_buf(data, data_len, us->srb);
 }
+EXPORT_SYMBOL_GPL(fill_inquiry_response);
 
 static int usb_stor_control_thread(void * __us)
 {
@@ -477,44 +423,92 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
        return 0;
 }
 
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
 /* Adjust device flags based on the "quirks=" module parameter */
 static void adjust_quirks(struct us_data *us)
 {
-       u16 vid, pid;
-       struct quirks_entry *q;
-       unsigned int mask = (US_FL_FIX_CAPACITY | US_FL_IGNORE_DEVICE |
+       char *p;
+       u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
+       u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
+       unsigned f = 0;
+       unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY |
+                       US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
                        US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
-                       US_FL_IGNORE_RESIDUE | US_FL_SINGLE_LUN |
-                       US_FL_NO_WP_DETECT);
-
-       vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
-       pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
-
-       for (q = quirks_list; q != quirks_end; ++q) {
-               if (q->vid == vid && q->pid == pid) {
-                       us->fflags = (us->fflags & ~mask) | q->fflags;
-                       dev_info(&us->pusb_intf->dev, "Quirks match for "
-                                       "vid %04x pid %04x: %x\n",
-                                       vid, pid, q->fflags);
+                       US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
+                       US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT);
+
+       p = quirks;
+       while (*p) {
+               /* Each entry consists of VID:PID:flags */
+               if (vid == simple_strtoul(p, &p, 16) &&
+                               *p == ':' &&
+                               pid == simple_strtoul(p+1, &p, 16) &&
+                               *p == ':')
                        break;
+
+               /* Move forward to the next entry */
+               while (*p) {
+                       if (*p++ == ',')
+                               break;
                }
        }
-}
+       if (!*p)        /* No match */
+               return;
 
-/* Find an unusual_dev descriptor (always succeeds in the current code) */
-static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
-{
-       const int id_index = id - storage_usb_ids;
-       return &us_unusual_dev_list[id_index];
+       /* Collect the flags */
+       while (*++p && *p != ',') {
+               switch (TOLOWER(*p)) {
+               case 'a':
+                       f |= US_FL_SANE_SENSE;
+                       break;
+               case 'b':
+                       f |= US_FL_BAD_SENSE;
+                       break;
+               case 'c':
+                       f |= US_FL_FIX_CAPACITY;
+                       break;
+               case 'h':
+                       f |= US_FL_CAPACITY_HEURISTICS;
+                       break;
+               case 'i':
+                       f |= US_FL_IGNORE_DEVICE;
+                       break;
+               case 'l':
+                       f |= US_FL_NOT_LOCKABLE;
+                       break;
+               case 'm':
+                       f |= US_FL_MAX_SECTORS_64;
+                       break;
+               case 'o':
+                       f |= US_FL_CAPACITY_OK;
+                       break;
+               case 'r':
+                       f |= US_FL_IGNORE_RESIDUE;
+                       break;
+               case 's':
+                       f |= US_FL_SINGLE_LUN;
+                       break;
+               case 'w':
+                       f |= US_FL_NO_WP_DETECT;
+                       break;
+               /* Ignore unrecognized flag characters */
+               }
+       }
+       us->fflags = (us->fflags & ~mask) | f;
+       dev_info(&us->pusb_intf->dev, "Quirks match for "
+                       "vid %04x pid %04x: %x\n",
+                       vid, pid, f);
 }
 
 /* Get the unusual_devs entries and the string descriptors */
-static int get_device_info(struct us_data *us, const struct usb_device_id *id)
+static int get_device_info(struct us_data *us, const struct usb_device_id *id,
+               struct us_unusual_dev *unusual_dev)
 {
        struct usb_device *dev = us->pusb_dev;
        struct usb_interface_descriptor *idesc =
                &us->pusb_intf->cur_altsetting->desc;
-       struct us_unusual_dev *unusual_dev = find_unusual(id);
 
        /* Store the entries */
        us->unusual_dev = unusual_dev;
@@ -579,7 +573,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
 }
 
 /* Get the transport settings */
-static int get_transport(struct us_data *us)
+static void get_transport(struct us_data *us)
 {
        switch (us->protocol) {
        case US_PR_CB:
@@ -591,7 +585,7 @@ static int get_transport(struct us_data *us)
 
        case US_PR_CBI:
                us->transport_name = "Control/Bulk/Interrupt";
-               us->transport = usb_stor_CBI_transport;
+               us->transport = usb_stor_CB_transport;
                us->transport_reset = usb_stor_CB_reset;
                us->max_lun = 7;
                break;
@@ -601,100 +595,11 @@ static int get_transport(struct us_data *us)
                us->transport = usb_stor_Bulk_transport;
                us->transport_reset = usb_stor_Bulk_reset;
                break;
-
-#ifdef CONFIG_USB_STORAGE_USBAT
-       case US_PR_USBAT:
-               us->transport_name = "Shuttle USBAT";
-               us->transport = usbat_transport;
-               us->transport_reset = usb_stor_CB_reset;
-               us->max_lun = 1;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
-       case US_PR_EUSB_SDDR09:
-               us->transport_name = "EUSB/SDDR09";
-               us->transport = sddr09_transport;
-               us->transport_reset = usb_stor_CB_reset;
-               us->max_lun = 0;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_SDDR55
-       case US_PR_SDDR55:
-               us->transport_name = "SDDR55";
-               us->transport = sddr55_transport;
-               us->transport_reset = sddr55_reset;
-               us->max_lun = 0;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DPCM
-       case US_PR_DPCM_USB:
-               us->transport_name = "Control/Bulk-EUSB/SDDR09";
-               us->transport = dpcm_transport;
-               us->transport_reset = usb_stor_CB_reset;
-               us->max_lun = 1;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_FREECOM
-       case US_PR_FREECOM:
-               us->transport_name = "Freecom";
-               us->transport = freecom_transport;
-               us->transport_reset = usb_stor_freecom_reset;
-               us->max_lun = 0;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DATAFAB
-       case US_PR_DATAFAB:
-               us->transport_name  = "Datafab Bulk-Only";
-               us->transport = datafab_transport;
-               us->transport_reset = usb_stor_Bulk_reset;
-               us->max_lun = 1;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_JUMPSHOT
-       case US_PR_JUMPSHOT:
-               us->transport_name  = "Lexar Jumpshot Control/Bulk";
-               us->transport = jumpshot_transport;
-               us->transport_reset = usb_stor_Bulk_reset;
-               us->max_lun = 1;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_ALAUDA
-       case US_PR_ALAUDA:
-               us->transport_name  = "Alauda Control/Bulk";
-               us->transport = alauda_transport;
-               us->transport_reset = usb_stor_Bulk_reset;
-               us->max_lun = 1;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_KARMA
-       case US_PR_KARMA:
-               us->transport_name = "Rio Karma/Bulk";
-               us->transport = rio_karma_transport;
-               us->transport_reset = usb_stor_Bulk_reset;
-               break;
-#endif
-
-       default:
-               return -EIO;
        }
-       US_DEBUGP("Transport: %s\n", us->transport_name);
-
-       /* fix for single-lun devices */
-       if (us->fflags & US_FL_SINGLE_LUN)
-               us->max_lun = 0;
-       return 0;
 }
 
 /* Get the protocol settings */
-static int get_protocol(struct us_data *us)
+static void get_protocol(struct us_data *us)
 {
        switch (us->subclass) {
        case US_SC_RBC:
@@ -704,19 +609,19 @@ static int get_protocol(struct us_data *us)
 
        case US_SC_8020:
                us->protocol_name = "8020i";
-               us->proto_handler = usb_stor_ATAPI_command;
+               us->proto_handler = usb_stor_pad12_command;
                us->max_lun = 0;
                break;
 
        case US_SC_QIC:
                us->protocol_name = "QIC-157";
-               us->proto_handler = usb_stor_qic157_command;
+               us->proto_handler = usb_stor_pad12_command;
                us->max_lun = 0;
                break;
 
        case US_SC_8070:
                us->protocol_name = "8070i";
-               us->proto_handler = usb_stor_ATAPI_command;
+               us->proto_handler = usb_stor_pad12_command;
                us->max_lun = 0;
                break;
 
@@ -729,26 +634,7 @@ static int get_protocol(struct us_data *us)
                us->protocol_name = "Uniform Floppy Interface (UFI)";
                us->proto_handler = usb_stor_ufi_command;
                break;
-
-#ifdef CONFIG_USB_STORAGE_ISD200
-       case US_SC_ISD200:
-               us->protocol_name = "ISD200 ATA/ATAPI";
-               us->proto_handler = isd200_ata_command;
-               break;
-#endif
-
-#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
-       case US_SC_CYP_ATACB:
-               us->protocol_name = "Transparent SCSI with Cypress ATACB";
-               us->proto_handler = cypress_atacb_passthrough;
-               break;
-#endif
-
-       default:
-               return -EIO;
        }
-       US_DEBUGP("Protocol: %s\n", us->protocol_name);
-       return 0;
 }
 
 /* Get the pipe settings */
@@ -796,12 +682,12 @@ static int get_pipes(struct us_data *us)
        us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
        us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
        us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
-               ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+               usb_endpoint_num(ep_out));
        us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, 
-               ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+               usb_endpoint_num(ep_in));
        if (ep_int) {
                us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
-                       ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+                       usb_endpoint_num(ep_int));
                us->ep_bInterval = ep_int->bInterval;
        }
        return 0;
@@ -929,14 +815,13 @@ static int usb_stor_scan_thread(void * __us)
 {
        struct us_data *us = (struct us_data *)__us;
 
-       printk(KERN_DEBUG
-               "usb-storage: device found at %d\n", us->pusb_dev->devnum);
+       dev_dbg(&us->pusb_intf->dev, "device found\n");
 
        set_freezable();
        /* 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");
+               dev_dbg(&us->pusb_intf->dev, "waiting for device to settle "
+                               "before scanning\n");
                wait_event_freezable_timeout(us->delay_wait,
                                test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
                                delay_use * HZ);
@@ -953,7 +838,7 @@ static int usb_stor_scan_thread(void * __us)
                        mutex_unlock(&us->dev_mutex);
                }
                scsi_scan_host(us_to_host(us));
-               printk(KERN_DEBUG "usb-storage: device scan complete\n");
+               dev_dbg(&us->pusb_intf->dev, "scan complete\n");
 
                /* Should we unbind if no devices were detected? */
        }
@@ -961,18 +846,25 @@ static int usb_stor_scan_thread(void * __us)
        complete_and_exit(&us->scanning_done, 0);
 }
 
+static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
 
-/* 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)
+       if (usb_dev->bus->sg_tablesize) {
+               return usb_dev->bus->sg_tablesize;
+       }
+       return SG_ALL;
+}
+
+/* First part of general USB mass-storage probing */
+int usb_stor_probe1(struct us_data **pus,
+               struct usb_interface *intf,
+               const struct usb_device_id *id,
+               struct us_unusual_dev *unusual_dev)
 {
        struct Scsi_Host *host;
        struct us_data *us;
        int result;
-       struct task_struct *th;
-
-       if (usb_usual_check_type(id, USB_US_TYPE_STOR))
-               return -ENXIO;
 
        US_DEBUGP("USB Mass Storage device detected\n");
 
@@ -991,7 +883,8 @@ static int storage_probe(struct usb_interface *intf,
         * Allow 16-byte CDBs and thus > 2TB
         */
        host->max_cmd_len = 16;
-       us = host_to_us(host);
+       host->sg_tablesize = usb_stor_sg_tablesize(intf);
+       *pus = us = host_to_us(host);
        memset(us, 0, sizeof(struct us_data));
        mutex_init(&(us->dev_mutex));
        init_completion(&us->cmnd_ready);
@@ -1004,24 +897,46 @@ static int storage_probe(struct usb_interface *intf,
        if (result)
                goto BadDevice;
 
-       /*
-        * Get the unusual_devs entries and the descriptors
-        *
-        * id_index is calculated in the declaration to be the index number
-        * of the match from the usb_device_id table, so we can find the
-        * corresponding entry in the private table.
-        */
-       result = get_device_info(us, id);
+       /* Get the unusual_devs entries and the descriptors */
+       result = get_device_info(us, id, unusual_dev);
        if (result)
                goto BadDevice;
 
-       /* Get the transport, protocol, and pipe settings */
-       result = get_transport(us);
-       if (result)
-               goto BadDevice;
-       result = get_protocol(us);
-       if (result)
+       /* Get standard transport and protocol settings */
+       get_transport(us);
+       get_protocol(us);
+
+       /* Give the caller a chance to fill in specialized transport
+        * or protocol settings.
+        */
+       return 0;
+
+BadDevice:
+       US_DEBUGP("storage_probe() failed\n");
+       release_everything(us);
+       return result;
+}
+EXPORT_SYMBOL_GPL(usb_stor_probe1);
+
+/* Second part of general USB mass-storage probing */
+int usb_stor_probe2(struct us_data *us)
+{
+       struct task_struct *th;
+       int result;
+
+       /* Make sure the transport and protocol have both been set */
+       if (!us->transport || !us->proto_handler) {
+               result = -ENXIO;
                goto BadDevice;
+       }
+       US_DEBUGP("Transport: %s\n", us->transport_name);
+       US_DEBUGP("Protocol: %s\n", us->protocol_name);
+
+       /* fix for single-lun devices */
+       if (us->fflags & US_FL_SINGLE_LUN)
+               us->max_lun = 0;
+
+       /* Find the endpoints and calculate pipe values */
        result = get_pipes(us);
        if (result)
                goto BadDevice;
@@ -1030,7 +945,9 @@ static int storage_probe(struct usb_interface *intf,
        result = usb_stor_acquire_resources(us);
        if (result)
                goto BadDevice;
-       result = scsi_add_host(host, &intf->dev);
+       snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
+                                       dev_name(&us->pusb_intf->dev));
+       result = scsi_add_host(us_to_host(us), &us->pusb_intf->dev);
        if (result) {
                printk(KERN_WARNING USB_STORAGE
                        "Unable to add the scsi host\n");
@@ -1058,9 +975,10 @@ BadDevice:
        release_everything(us);
        return result;
 }
+EXPORT_SYMBOL_GPL(usb_stor_probe2);
 
-/* Handle a disconnect event from the USB core */
-static void storage_disconnect(struct usb_interface *intf)
+/* Handle a USB mass-storage disconnect */
+void usb_stor_disconnect(struct usb_interface *intf)
 {
        struct us_data *us = usb_get_intfdata(intf);
 
@@ -1068,6 +986,42 @@ static void storage_disconnect(struct usb_interface *intf)
        quiesce_and_remove_host(us);
        release_everything(us);
 }
+EXPORT_SYMBOL_GPL(usb_stor_disconnect);
+
+/* The main probe routine for standard devices */
+static int storage_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct us_data *us;
+       int result;
+
+       /*
+        * If libusual is configured, let it decide whether a standard
+        * device should be handled by usb-storage or by ub.
+        * If the device isn't standard (is handled by a subdriver
+        * module) then don't accept it.
+        */
+       if (usb_usual_check_type(id, USB_US_TYPE_STOR) ||
+                       usb_usual_ignore_device(intf))
+               return -ENXIO;
+
+       /*
+        * Call the general probe procedures.
+        *
+        * The unusual_dev_list array is parallel to the usb_storage_usb_ids
+        * table, so we use the index of the id entry to find the
+        * corresponding unusual_devs entry.
+        */
+       result = usb_stor_probe1(&us, intf, id,
+                       (id - usb_storage_usb_ids) + us_unusual_dev_list);
+       if (result)
+               return result;
+
+       /* No special transport or protocol settings in the main module */
+
+       result = usb_stor_probe2(us);
+       return result;
+}
 
 /***********************************************************************
  * Initialization and registration
@@ -1076,100 +1030,21 @@ static void storage_disconnect(struct usb_interface *intf)
 static struct usb_driver usb_storage_driver = {
        .name =         "usb-storage",
        .probe =        storage_probe,
-       .disconnect =   storage_disconnect,
-#ifdef CONFIG_PM
-       .suspend =      storage_suspend,
-       .resume =       storage_resume,
-       .reset_resume = storage_reset_resume,
-#endif
-       .pre_reset =    storage_pre_reset,
-       .post_reset =   storage_post_reset,
-       .id_table =     storage_usb_ids,
+       .disconnect =   usb_stor_disconnect,
+       .suspend =      usb_stor_suspend,
+       .resume =       usb_stor_resume,
+       .reset_resume = usb_stor_reset_resume,
+       .pre_reset =    usb_stor_pre_reset,
+       .post_reset =   usb_stor_post_reset,
+       .id_table =     usb_storage_usb_ids,
        .soft_unbind =  1,
 };
 
-/* Works only for digits and letters, but small and fast */
-#define TOLOWER(x) ((x) | 0x20)
-
-static void __init parse_quirks(void)
-{
-       int n, i;
-       char *p;
-
-       if (!quirks)
-               return;
-
-       /* Count the ':' characters to get 2 * the number of entries */
-       n = 0;
-       for (p = quirks; *p; ++p) {
-               if (*p == ':')
-                       ++n;
-       }
-       n /= 2;
-       if (n == 0)
-               return;         /* Don't allocate 0 bytes */
-
-       quirks_list = kmalloc(n * sizeof(*quirks_list), GFP_KERNEL);
-       if (!quirks_list)
-               return;
-
-       p = quirks;
-       quirks_end = quirks_list;
-       for (i = 0; i < n && *p; ++i) {
-               unsigned f = 0;
-
-               /* Each entry consists of VID:PID:flags */
-               quirks_end->vid = simple_strtoul(p, &p, 16);
-               if (*p != ':')
-                       goto skip_to_next;
-               quirks_end->pid = simple_strtoul(p+1, &p, 16);
-               if (*p != ':')
-                       goto skip_to_next;
-
-               while (*++p && *p != ',') {
-                       switch (TOLOWER(*p)) {
-                       case 'c':
-                               f |= US_FL_FIX_CAPACITY;
-                               break;
-                       case 'i':
-                               f |= US_FL_IGNORE_DEVICE;
-                               break;
-                       case 'l':
-                               f |= US_FL_NOT_LOCKABLE;
-                               break;
-                       case 'm':
-                               f |= US_FL_MAX_SECTORS_64;
-                               break;
-                       case 'r':
-                               f |= US_FL_IGNORE_RESIDUE;
-                               break;
-                       case 's':
-                               f |= US_FL_SINGLE_LUN;
-                               break;
-                       case 'w':
-                               f |= US_FL_NO_WP_DETECT;
-                               break;
-                       /* Ignore unrecognized flag characters */
-                       }
-               }
-               quirks_end->fflags = f;
-               ++quirks_end;
-
- skip_to_next:
-               /* Entries are separated by commas */
-               while (*p) {
-                       if (*p++ == ',')
-                               break;
-               }
-       } /* for (i = 0; ...) */
-}
-
 static int __init usb_stor_init(void)
 {
        int retval;
 
        printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
-       parse_quirks();
 
        /* register the driver, return usb_register return code if error */
        retval = usb_register(&usb_storage_driver);