|
@@ -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)
|
|
@@ -118,36 +118,8 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
|
|
|
|
|
|
/*
|
|
|
* 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 COMPLIANT_DEV UNUSUAL_DEV
|
|
|
-
|
|
|
-#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 COMPLIANT_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
|
|
@@ -179,18 +151,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 COMPLIANT_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);
|
|
|
|
|
@@ -207,8 +178,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);
|
|
|
|
|
@@ -221,8 +193,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);
|
|
|
|
|
@@ -235,6 +208,7 @@ static int storage_reset_resume(struct usb_interface *iface)
|
|
|
* the device */
|
|
|
return 0;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(usb_stor_reset_resume);
|
|
|
|
|
|
#endif /* CONFIG_PM */
|
|
|
|
|
@@ -243,7 +217,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);
|
|
|
|
|
@@ -253,8 +227,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);
|
|
|
|
|
@@ -269,6 +244,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
|
|
@@ -311,6 +287,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)
|
|
|
{
|
|
@@ -551,20 +528,13 @@ static void adjust_quirks(struct us_data *us)
|
|
|
vid, pid, f);
|
|
|
}
|
|
|
|
|
|
-/* 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];
|
|
|
-}
|
|
|
-
|
|
|
/* 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;
|
|
@@ -629,7 +599,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:
|
|
@@ -732,19 +702,11 @@ static int get_transport(struct us_data *us)
|
|
|
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:
|
|
@@ -794,11 +756,7 @@ static int get_protocol(struct us_data *us)
|
|
|
break;
|
|
|
#endif
|
|
|
|
|
|
- default:
|
|
|
- return -EIO;
|
|
|
}
|
|
|
- US_DEBUGP("Protocol: %s\n", us->protocol_name);
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
/* Get the pipe settings */
|
|
@@ -1012,17 +970,15 @@ static int usb_stor_scan_thread(void * __us)
|
|
|
}
|
|
|
|
|
|
|
|
|
-/* 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)
|
|
|
+/* 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");
|
|
|
|
|
@@ -1041,7 +997,7 @@ 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);
|
|
|
+ *pus = us = host_to_us(host);
|
|
|
memset(us, 0, sizeof(struct us_data));
|
|
|
mutex_init(&(us->dev_mutex));
|
|
|
init_completion(&us->cmnd_ready);
|
|
@@ -1054,24 +1010,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;
|
|
@@ -1080,7 +1058,7 @@ 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);
|
|
|
+ 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");
|
|
@@ -1108,9 +1086,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);
|
|
|
|
|
@@ -1118,6 +1097,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
|
|
@@ -1126,15 +1141,13 @@ 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,
|
|
|
};
|
|
|
|