summaryrefslogtreecommitdiffstats
path: root/drivers/usb/storage/usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r--drivers/usb/storage/usb.c425
1 files changed, 157 insertions, 268 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 6c254c701..1e0f40f50 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1,6 +1,6 @@
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.57 2000/11/21 02:56:41 mdharm Exp $
+ * $Id: usb.c,v 1.61 2001/01/13 00:10:59 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -11,6 +11,9 @@
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
*
+ * usb_device_id support by Adam J. Richter (adam@yggdrasil.com):
+ * (c) 2000 Yggdrasil Computing, Inc.
+ *
* This driver is based on the 'USB Mass Storage Class' document. This
* describes in detail the protocol used to communicate with such
* devices. Clearly, the designers had SCSI and ATAPI commands in
@@ -95,11 +98,133 @@ struct semaphore us_list_semaphore;
static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
+
static void storage_disconnect(struct usb_device *dev, void *ptr);
+
+/* The entries in this table, except for final ones here
+ * (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
+ * line for line with the entries of us_unsuaul_dev_list[].
+ * For now, we duplicate idVendor and idProduct in us_unsual_dev_list,
+ * just to avoid alignment bugs.
+ */
+
+#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName,useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax) }
+
+static struct usb_device_id storage_usb_ids [] = {
+
+# include "unusual_devs.h"
+#undef UNUSUAL_DEV
+ /* Control/Bulk transport for all SubClass values */
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CB) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CB) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CB) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CB) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CB) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CB) },
+
+ /* Control/Bulk/Interrupt transport for all SubClass values */
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_CBI) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_CBI) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_CBI) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_CBI) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_CBI) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_CBI) },
+
+ /* Bulk-only transport for all SubClass values */
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_RBC, US_PR_BULK) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8020, US_PR_BULK) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_QIC, US_PR_BULK) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_UFI, US_PR_BULK) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_8070, US_PR_BULK) },
+ { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
+
+ /* Terminating entry */
+ { }
+};
+
+MODULE_DEVICE_TABLE (usb, storage_usb_ids);
+
+/* 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
+ * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
+ * normally generated by a device thorugh the INQUIRY response will be
+ * taken from this list, and this is the reason for the above size
+ * restriction. However, if the flag is not present, then you
+ * are free to use as many characters as you like.
+ */
+
+#undef UNUSUAL_DEV
+#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
+ vendor_name, product_name, use_protocol, use_transport, \
+ init_function, Flags) \
+{ \
+ vendorName: vendor_name, \
+ productName: product_name, \
+ useProtocol: use_protocol, \
+ useTransport: use_transport, \
+ initFunction : init_function, \
+ flags: Flags, \
+}
+
+static struct us_unusual_dev us_unusual_dev_list[] = {
+# include "unusual_devs.h"
+# undef UNUSUAL_DEV
+ /* Control/Bulk transport for all SubClass values */
+ { useProtocol: US_SC_RBC,
+ useTransport: US_PR_CB},
+ { useProtocol: US_SC_8020,
+ useTransport: US_PR_CB},
+ { useProtocol: US_SC_QIC,
+ useTransport: US_PR_CB},
+ { useProtocol: US_SC_UFI,
+ useTransport: US_PR_CB},
+ { useProtocol: US_SC_8070,
+ useTransport: US_PR_CB},
+ { useProtocol: US_SC_SCSI,
+ useTransport: US_PR_CB},
+
+ /* Control/Bulk/Interrupt transport for all SubClass values */
+ { useProtocol: US_SC_RBC,
+ useTransport: US_PR_CBI},
+ { useProtocol: US_SC_8020,
+ useTransport: US_PR_CBI},
+ { useProtocol: US_SC_QIC,
+ useTransport: US_PR_CBI},
+ { useProtocol: US_SC_UFI,
+ useTransport: US_PR_CBI},
+ { useProtocol: US_SC_8070,
+ useTransport: US_PR_CBI},
+ { useProtocol: US_SC_SCSI,
+ useTransport: US_PR_CBI},
+
+ /* Bulk-only transport for all SubClass values */
+ { useProtocol: US_SC_RBC,
+ useTransport: US_PR_BULK},
+ { useProtocol: US_SC_8020,
+ useTransport: US_PR_BULK},
+ { useProtocol: US_SC_QIC,
+ useTransport: US_PR_BULK},
+ { useProtocol: US_SC_UFI,
+ useTransport: US_PR_BULK},
+ { useProtocol: US_SC_8070,
+ useTransport: US_PR_BULK},
+ { useProtocol: US_SC_SCSI,
+ useTransport: US_PR_BULK},
+
+ /* Terminating entry */
+ { 0 }
+};
+
struct usb_driver usb_storage_driver = {
name: "usb-storage",
probe: storage_probe,
disconnect: storage_disconnect,
+ id_table: storage_usb_ids,
};
/*
@@ -325,246 +450,6 @@ static int usb_stor_control_thread(void * __us)
return 0;
}
-/* 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
- * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
- * normally generated by a device thorugh the INQUIRY response will be
- * taken from this list, and this is the reason for the above size
- * restriction. However, if the flag is not present, then you
- * are free to use as many characters as you like.
- */
-static struct us_unusual_dev us_unusual_dev_list[] = {
-
- { 0x03ee, 0x0000, 0x0000, 0x0245,
- "Mitsumi",
- "CD-R/RW Drive",
- US_SC_8020, US_PR_CBI, NULL, 0},
-
- { 0x03f0, 0x0107, 0x0200, 0x0200,
- "HP",
- "CD-Writer+",
- US_SC_8070, US_PR_CB, NULL, 0},
-
-#ifdef CONFIG_USB_STORAGE_HP8200e
- { 0x03f0, 0x0207, 0x0001, 0x0001,
- "HP",
- "CD-Writer+ 8200e",
- US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0},
-#endif
-
- { 0x04e6, 0x0001, 0x0200, 0x0200,
- "Matshita",
- "LS-120",
- US_SC_8020, US_PR_CB, NULL, 0},
-
- { 0x04e6, 0x0002, 0x0100, 0x0100,
- "Shuttle",
- "eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG },
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- { 0x04e6, 0x0003, 0x0000, 0x9999,
- "Sandisk",
- "ImageMate SDDR09",
- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP },
-#endif
-
-#ifdef CONFIG_USB_STORAGE_DPCM
- { 0x0436, 0x0005, 0x0100, 0x0100,
- "Microtech",
- "CameraMate (DPCM_USB)",
- US_SC_SCSI, US_PR_DPCM_USB, NULL,
- US_FL_START_STOP },
-#endif
-
- { 0x04e6, 0x0006, 0x0100, 0x0200,
- "Shuttle",
- "eUSB MMC Adapter",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN},
-
- { 0x04e6, 0x0007, 0x0100, 0x0200,
- "Sony",
- "Hifd",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN},
-
- { 0x04e6, 0x0009, 0x0200, 0x0200,
- "Shuttle",
- "eUSB ATA/ATAPI Adapter",
- US_SC_8020, US_PR_CB, NULL, 0},
-
- { 0x04e6, 0x000a, 0x0200, 0x0200,
- "Shuttle",
- "eUSB CompactFlash Adapter",
- US_SC_8020, US_PR_CB, NULL, 0},
-
- { 0x04e6, 0x000B, 0x0100, 0x0100,
- "Shuttle",
- "eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG },
-
- { 0x04e6, 0x000C, 0x0100, 0x0100,
- "Shuttle",
- "eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG },
-
- { 0x04e6, 0x0101, 0x0200, 0x0200,
- "Shuttle",
- "CD-RW Device",
- US_SC_8020, US_PR_CB, NULL, 0},
-
- { 0x054c, 0x0010, 0x0106, 0x0210,
- "Sony",
- "DSC-S30/S70/505V/F505",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
-
- { 0x054c, 0x002d, 0x0100, 0x0100,
- "Sony",
- "Memorystick MSAC-US1",
- US_SC_UFI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP },
-
- { 0x057b, 0x0000, 0x0000, 0x0299,
- "Y-E Data",
- "Flashbuster-U",
- US_SC_UFI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN},
-
- { 0x057b, 0x0000, 0x0300, 0x9999,
- "Y-E Data",
- "Flashbuster-U",
- US_SC_UFI, US_PR_CBI, NULL,
- US_FL_SINGLE_LUN},
-
- { 0x059f, 0xa601, 0x0200, 0x0200,
- "LaCie",
- "USB Hard Disk",
- US_SC_RBC, US_PR_CB, NULL, 0 },
-
- { 0x05ab, 0x0031, 0x0100, 0x0100,
- "In-System",
- "USB/IDE Bridge (ATAPI ONLY!)",
- US_SC_8070, US_PR_BULK, NULL, 0 },
-
- { 0x0644, 0x0000, 0x0100, 0x0100,
- "TEAC",
- "Floppy Drive",
- US_SC_UFI, US_PR_CB, NULL, 0 },
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- { 0x066b, 0x0105, 0x0100, 0x0100,
- "Olympus",
- "Camedia MAUSB-2",
- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP },
-#endif
-
- { 0x0693, 0x0002, 0x0100, 0x0100,
- "Hagiwara",
- "FlashGate SmartMedia",
- US_SC_SCSI, US_PR_BULK, NULL, 0 },
-
- { 0x0693, 0x0005, 0x0100, 0x0100,
- "Hagiwara",
- "Flashgate",
- US_SC_SCSI, US_PR_BULK, NULL, 0 },
-
- { 0x0781, 0x0001, 0x0200, 0x0200,
- "Sandisk",
- "ImageMate SDDR-05a",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP},
-
- { 0x0781, 0x0100, 0x0100, 0x0100,
- "Sandisk",
- "ImageMate SDDR-12",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN },
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- { 0x0781, 0x0200, 0x0100, 0x0208,
- "Sandisk",
- "ImageMate SDDR-09",
- US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
- US_FL_SINGLE_LUN | US_FL_START_STOP },
-#endif
-
- { 0x0781, 0x0002, 0x0009, 0x0009,
- "Sandisk",
- "ImageMate SDDR-31",
- US_SC_SCSI, US_PR_BULK, NULL,
- US_FL_IGNORE_SER},
-
- { 0x07af, 0x0004, 0x0100, 0x0100,
- "Microtech",
- "USB-SCSI-DB25",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG },
-
-#ifdef CONFIG_USB_STORAGE_FREECOM
- { 0x07ab, 0xfc01, 0x0000, 0x9999,
- "Freecom",
- "USB-IDE",
- US_SC_QIC, US_PR_FREECOM, freecom_init, 0},
-#endif
-
- { 0x07af, 0x0005, 0x0100, 0x0100,
- "Microtech",
- "USB-SCSI-HD50",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG },
-
-#ifdef CONFIG_USB_STORAGE_DPCM
- { 0x07af, 0x0006, 0x0100, 0x0100,
- "Microtech",
- "CameraMate (DPCM_USB)",
- US_SC_SCSI, US_PR_DPCM_USB, NULL,
- US_FL_START_STOP },
-#endif
- { 0 }
-};
-
-/* Search our ususual device list, based on vendor/product combinations
- * to see if we can support this device. Returns a pointer to a structure
- * defining how we should support this device, or NULL if it's not in the
- * list
- */
-static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
- u16 bcdDevice)
-{
- struct us_unusual_dev* ptr;
-
- US_DEBUGP("Searching unusual device list for (0x%x, 0x%x, 0x%x)...\n",
- idVendor, idProduct, bcdDevice);
-
- ptr = us_unusual_dev_list;
- while ((ptr->idVendor != 0x0000) &&
- !((ptr->idVendor == idVendor) &&
- (ptr->idProduct == idProduct) &&
- (ptr->bcdDeviceMin <= bcdDevice) &&
- (ptr->bcdDeviceMax >= bcdDevice)))
- ptr++;
-
- /* if the search ended because we hit the end record, we failed */
- if (ptr->idVendor == 0x0000) {
- US_DEBUGP("-- did not find a matching device\n");
- return NULL;
- }
-
- /* otherwise, we found one! */
- US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName,
- ptr->productName);
- return ptr;
-}
-
/* Set up the IRQ pipe and handler
* Note that this function assumes that all the data in the us_data
* strucuture is current. This includes the ep_int field, which gives us
@@ -620,6 +505,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
int i;
+ const int id_index = id - storage_usb_ids;
char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */
@@ -640,47 +526,48 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
u8 subclass = 0;
u8 protocol = 0;
- /* the altsettting 0 on the interface we're probing */
- struct usb_interface_descriptor *altsetting =
- &(dev->actconfig->interface[ifnum].altsetting[0]);
+ /* the altsettting on the interface we're probing that matched our
+ * usb_match_id table
+ */
+ struct usb_interface *intf = dev->actconfig->interface;
+ struct usb_interface_descriptor *altsetting =
+ intf[ifnum].altsetting + intf[ifnum].act_altsetting;
+ US_DEBUGP("act_altsettting is %d\n", intf[ifnum].act_altsetting);
/* clear the temporary strings */
memset(mf, 0, sizeof(mf));
memset(prod, 0, sizeof(prod));
memset(serial, 0, sizeof(serial));
- /* search for this device in our unusual device list */
- unusual_dev = us_find_dev(dev->descriptor.idVendor,
- dev->descriptor.idProduct,
- dev->descriptor.bcdDevice);
-
/*
* Can we support this device, either because we know about it
* from our unusual device list, or because it advertises that it's
* compliant to the specification?
+ *
+ * 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.
*/
- if (!unusual_dev &&
- !(dev->descriptor.bDeviceClass == 0 &&
- altsetting->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
- altsetting->bInterfaceSubClass >= US_SC_MIN &&
- altsetting->bInterfaceSubClass <= US_SC_MAX)) {
- /* if it's not a mass storage, we go no further */
+ US_DEBUGP("id_index calculated to be: %d\n", id_index);
+ US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0]));
+ if (id_index <
+ sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) {
+ unusual_dev = &us_unusual_dev_list[id_index];
+ if (unusual_dev->vendorName)
+ US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName);
+ if (unusual_dev->productName)
+ US_DEBUGP("Product: %s\n", unusual_dev->productName);
+ } else
+ /* no, we can't support it */
return NULL;
- }
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
/* Determine subclass and protocol, or copy from the interface */
- if (unusual_dev) {
- subclass = unusual_dev->useProtocol;
- protocol = unusual_dev->useTransport;
- flags = unusual_dev->flags;
- } else {
- subclass = altsetting->bInterfaceSubClass;
- protocol = altsetting->bInterfaceProtocol;
- flags = 0;
- }
+ subclass = unusual_dev->useProtocol;
+ protocol = unusual_dev->useTransport;
+ flags = unusual_dev->flags;
/*
* Find the endpoints we need
@@ -728,7 +615,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
- US_DEBUGP("Sanity check failed. Rejecting device.\n");
+ US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
return NULL;
}
@@ -861,7 +748,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
strncpy(ss->product, prod, USB_STOR_STRING_LEN);
strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
if (strlen(ss->vendor) == 0) {
- if (unusual_dev)
+ if (unusual_dev->vendorName)
strncpy(ss->vendor, unusual_dev->vendorName,
USB_STOR_STRING_LEN);
else
@@ -869,7 +756,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
USB_STOR_STRING_LEN);
}
if (strlen(ss->product) == 0) {
- if (unusual_dev)
+ if (unusual_dev->productName)
strncpy(ss->product, unusual_dev->productName,
USB_STOR_STRING_LEN);
else
@@ -1118,6 +1005,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
int __init usb_stor_init(void)
{
+ printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
+
/* initialize internal global data elements */
us_list = NULL;
init_MUTEX(&us_list_semaphore);