diff options
Diffstat (limited to 'drivers/usb/storage/usb.c')
-rw-r--r-- | drivers/usb/storage/usb.c | 285 |
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"); |