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.c285
1 files changed, 229 insertions, 56 deletions
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index fc70bc72a..50ebddd6f 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.16 2000/08/01 22:01:19 mdharm Exp $
+ * $Id: usb.c,v 1.23 2000/08/08 20:46:45 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -44,7 +44,6 @@
*/
#include <linux/config.h>
-
#include "usb.h"
#include "scsiglue.h"
#include "transport.h"
@@ -56,6 +55,9 @@
#ifdef CONFIG_USB_STORAGE_SDDR09
#include "sddr09.h"
#endif
+#ifdef CONFIG_USB_STORAGE_DPCM
+#include "dpcm.h"
+#endif
#include <linux/module.h>
#include <linux/sched.h>
@@ -63,6 +65,10 @@
#include <linux/init.h>
#include <linux/malloc.h>
+/* Some informational data */
+MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
+MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
+
/*
* Per device data
*/
@@ -91,6 +97,58 @@ static struct usb_driver storage_driver = {
disconnect: storage_disconnect,
};
+/*
+ * fill_inquiry_response takes an unsigned char array (which must
+ * be at least 36 characters) and populates the vendor name,
+ * product name, and revision fields. Then the array is copied
+ * into the SCSI command's response buffer (oddly enough
+ * called request_buffer). data_len contains the length of the
+ * data array, which again must be at least 36.
+ */
+
+void fill_inquiry_response(struct us_data *us, unsigned char *data,
+ unsigned int data_len) {
+
+ int i;
+ struct scatterlist *sg;
+ int len =
+ us->srb->request_bufflen > data_len ? data_len :
+ us->srb->request_bufflen;
+ int transferred;
+ int amt;
+
+ if (data_len<36) // You lose.
+ return;
+
+ 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);
+
+ if (us->srb->use_sg) {
+ sg = (struct scatterlist *)us->srb->request_buffer;
+ for (i=0; i<us->srb->use_sg; i++)
+ memset(sg[i].address, 0, sg[i].length);
+ for (i=0, transferred=0;
+ i<us->srb->use_sg && transferred < len;
+ i++) {
+ amt = sg[i].length > len-transferred ?
+ len-transferred : sg[i].length;
+ memcpy(sg[i].address, data+transferred, amt);
+ transferred -= amt;
+ }
+ } else {
+ memset(us->srb->request_buffer, 0, us->srb->request_bufflen);
+ memcpy(us->srb->request_buffer, data, len);
+ }
+}
+
static int usb_stor_control_thread(void * __us)
{
wait_queue_t wait;
@@ -176,7 +234,7 @@ static int usb_stor_control_thread(void * __us)
us->srb = NULL;
break;
}
-
+
/* lock the device pointers */
down(&(us->dev_semaphore));
@@ -246,50 +304,140 @@ static int usb_stor_control_thread(void * __us)
}
/* 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[] = {
- { 0x03f0, 0x0107, 0x0200, 0x0200, "HP USB CD-Writer Plus",
- US_SC_8070, US_PR_CB, 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 USB CD-Writer Plus 8200e",
- US_SC_8070, US_PR_SCM_ATAPI,
- US_FL_ALT_LENGTH | US_FL_NEED_INIT | US_FL_SINGLE_LUN},
+ { 0x03f0, 0x0207, 0x0001, 0x0001,
+ "HP",
+ "CD-Writer+ 8200e",
+ US_SC_8070, US_PR_SCM_ATAPI, init_8200e,
+ US_FL_SINGLE_LUN},
#endif
- { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita LS-120",
- US_SC_8020, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x04e6, 0x0006, 0x0100, 0x0100, "Shuttle eUSB MMC Adapter",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x054c, 0x0010, 0x0210, 0x0210, "Sony DSC-S30/S70",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
- US_FL_MODE_XLATE | US_FL_ALT_LENGTH | US_FL_ALT_LENGTH},
- { 0x054c, 0x002d, 0x0100, 0x0100, "Sony Memorystick MSAC-US1",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP |
- US_FL_MODE_XLATE | US_FL_ALT_LENGTH},
- { 0x057b, 0x0000, 0x0000, 0x0299, "Y-E Data Flashbuster-U",
- US_SC_UFI, US_PR_CB, US_FL_SINGLE_LUN},
- { 0x057b, 0x0000, 0x0300, 0x9999, "Y-E Data Flashbuster-U",
- US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN},
- { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-05a)",
- US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP},
-#ifdef CONFIG_USB_STORAGE_SDDR09
- { 0x0781, 0x0200, 0x0100, 0x0100, "Sandisk ImageMate (SDDR-09)",
- US_SC_SCSI, US_PR_EUSB_SDDR09,
+
+ { 0x04e6, 0x0001, 0x0200, 0x0200,
+ "Matshita",
+ "LS-120",
+ US_SC_8020, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x04e6, 0x0002, 0x0100, 0x0100,
+ "Shuttle",
+ "eUSCSI Bridge",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x04e6, 0x0006, 0x0100, 0x0100,
+ "Shuttle",
+ "eUSB MMC Adapter",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN},
+
+ { 0x054c, 0x0010, 0x0210, 0x0210,
+ "Sony",
+ "DSC-S30/S70",
+ 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_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE },
+
+ { 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},
+
+ { 0x0693, 0x0002, 0x0100, 0x0100,
+ "Hagiwara",
+ "FlashGate SmartMedia",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x0781, 0x0001, 0x0200, 0x0200,
+ "Sandisk",
+ "ImageMate SDDR05a",
+ US_SC_SCSI, US_PR_CB, NULL,
US_FL_SINGLE_LUN | US_FL_START_STOP},
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+ { 0x0781, 0x0200, 0x0100, 0x0100,
+ "Sandisk",
+ "ImageMate SDDR09",
+ US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+ US_FL_SINGLE_LUN | US_FL_START_STOP },
+#endif
+
+ { 0x0781, 0x0002, 0x0009, 0x0009,
+ "Sandisk",
+ "ImageMate SDDR31",
+ 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, NULL,
+ 0 },
+
+ { 0x059f, 0xa601, 0x0200, 0x0200,
+ "LaCie",
+ "USB Hard Disk",
+ US_SC_RBC, US_PR_CB, NULL,
+ 0 },
+
+#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
- { 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)",
- US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER},
- { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech USB-SCSI-DB25",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech USB-SCSI-HD50",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System USB/IDE Bridge",
- US_SC_8070, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0693, 0x0005, 0x0100, 0x0100, "Hagiwara Flashgate",
- US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0 }};
+
+ { 0x07af, 0x0005, 0x0100, 0x0100,
+ "Microtech",
+ "USB-SCSI-HD50",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x05ab, 0x0031, 0x0100, 0x0100,
+ "In-System",
+ "USB/IDE Bridge",
+ US_SC_8070, US_PR_BULK, NULL,
+ 0 },
+
+ { 0x0693, 0x0005, 0x0100, 0x0100,
+ "Hagiwara",
+ "Flashgate",
+ US_SC_SCSI, US_PR_BULK, NULL,
+ 0 },
+
+ { 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
@@ -319,7 +467,8 @@ static struct us_unusual_dev* us_find_dev(u16 idVendor, u16 idProduct,
}
/* otherwise, we found one! */
- US_DEBUGP("-- found matching device: %s\n", ptr->name);
+ US_DEBUGP("-- found matching device: %s %s\n", ptr->vendorName,
+ ptr->productName);
return ptr;
}
@@ -546,15 +695,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
USB_ENDPOINT_NUMBER_MASK;
ss->ep_int = ep_int;
- /* Reset the device's NEED_INIT flag if it needs to be
- initialized with a magic sequence */
-
- if (flags & US_FL_NEED_INIT)
- ss->flags |= US_FL_NEED_INIT;
-
/* allocate an IRQ callback if one is needed */
if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
return NULL;
+
+ /* Re-Initialize the device if it needs it */
+
+ if (unusual_dev && unusual_dev->initFunction)
+ (*unusual_dev->initFunction)(ss);
+
} else {
/* New device -- allocate memory and initialize */
US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid));
@@ -586,6 +735,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->subclass = subclass;
ss->protocol = protocol;
ss->flags = flags;
+ ss->unusual_dev = unusual_dev;
/* copy over the endpoint data */
if (ep_in)
@@ -604,10 +754,22 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
strncpy(ss->vendor, mf, USB_STOR_STRING_LEN);
strncpy(ss->product, prod, USB_STOR_STRING_LEN);
strncpy(ss->serial, serial, USB_STOR_STRING_LEN);
- if (strlen(ss->vendor) == 0)
- strncpy(ss->vendor, "Unknown", USB_STOR_STRING_LEN);
- if (strlen(ss->product) == 0)
- strncpy(ss->product, "Unknown", USB_STOR_STRING_LEN);
+ if (strlen(ss->vendor) == 0) {
+ if (unusual_dev)
+ strncpy(ss->vendor, unusual_dev->vendorName,
+ USB_STOR_STRING_LEN);
+ else
+ strncpy(ss->vendor, "Unknown",
+ USB_STOR_STRING_LEN);
+ }
+ if (strlen(ss->product) == 0) {
+ if (unusual_dev)
+ strncpy(ss->product, unusual_dev->productName,
+ USB_STOR_STRING_LEN);
+ else
+ strncpy(ss->product, "Unknown",
+ USB_STOR_STRING_LEN);
+ }
if (strlen(ss->serial) == 0)
strncpy(ss->serial, "None", USB_STOR_STRING_LEN);
@@ -657,6 +819,15 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
ss->max_lun = 1;
break;
#endif
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+ case US_PR_DPCM_USB:
+ ss->transport_name = "Control/Bulk-EUSB/SDDR09";
+ ss->transport = dpcm_transport;
+ ss->transport_reset = usb_stor_CB_reset;
+ ss->max_lun = 1;
+ break;
+#endif
default:
ss->transport_name = "Unknown";
@@ -734,6 +905,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum)
* we to do it?
*/
(struct us_data *)ss->htmplt.proc_dir = ss;
+
+ /* Just before we start our control thread, initialize
+ * the device if it needs initialization */
+ if (unusual_dev && unusual_dev->initFunction)
+ (*unusual_dev->initFunction)(ss);
/* start up our control thread */
ss->pid = kernel_thread(usb_stor_control_thread, ss,
@@ -878,6 +1054,3 @@ void __exit usb_stor_exit(void)
module_init(usb_stor_init) ;
module_exit(usb_stor_exit) ;
-
-MODULE_AUTHOR("Michael Gee <michael@linuxspecific.com>, David L. Brown, Jr. <usb-storage@davidb.org>, Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
-MODULE_DESCRIPTION("USB Mass Storage driver");