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