Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
new file mode 100644
index 0000000..f1f1c06
--- /dev/null
+++ b/drivers/usb/storage/Kconfig
@@ -0,0 +1,113 @@
+#
+# USB Storage driver configuration
+#
+
+comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information"
+	depends on USB
+
+config USB_STORAGE
+	tristate "USB Mass Storage support"
+	depends on USB
+	select SCSI
+	---help---
+	  Say Y here if you want to connect USB mass storage devices to your
+	  computer's USB port. This is the driver you need for USB
+	  floppy drives, USB hard disks, USB tape drives, USB CD-ROMs,
+	  USB flash devices, and memory sticks, along with
+	  similar devices. This driver may also be used for some cameras
+	  and card readers.
+
+	  This option 'selects' (turns on, enables) 'SCSI', but you
+	  probably also need 'SCSI device support: SCSI disk support'
+	  (BLK_DEV_SD) for most USB storage devices.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called usb-storage.
+
+config USB_STORAGE_DEBUG
+	bool "USB Mass Storage verbose debug"
+	depends on USB_STORAGE
+	help
+	  Say Y here in order to have the USB Mass Storage code generate
+	  verbose debugging messages.
+
+config USB_STORAGE_DATAFAB
+	bool "Datafab Compact Flash Reader support (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Support for certain Datafab CompactFlash readers.
+	  Datafab has a web page at <http://www.datafabusa.com/>.
+
+config USB_STORAGE_FREECOM
+	bool "Freecom USB/ATAPI Bridge support"
+	depends on USB_STORAGE
+	help
+	  Support for the Freecom USB to IDE/ATAPI adaptor.
+	  Freecom has a web page at <http://www.freecom.de/>.
+
+config USB_STORAGE_ISD200
+	bool "ISD-200 USB/ATA Bridge support"
+	depends on USB_STORAGE && BLK_DEV_IDE
+	---help---
+	  Say Y here if you want to use USB Mass Store devices based
+	  on the In-Systems Design ISD-200 USB/ATA bridge.
+
+	  Some of the products that use this chip are:
+
+	  - Archos Jukebox 6000
+	  - ISD SmartCable for Storage
+	  - Taiwan Skymaster CD530U/DEL-0241 IDE bridge
+	  - Sony CRX10U CD-R/RW drive
+	  - CyQ've CQ8060A CDRW drive
+	  - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
+
+config USB_STORAGE_DPCM
+	bool "Microtech/ZiO! CompactFlash/SmartMedia support"
+	depends on USB_STORAGE
+	help
+	  Say Y here to support the Microtech/ZiO! CompactFlash reader.
+	  There is a web page at <http://www.ziocorp.com/products/>.
+
+config USB_STORAGE_USBAT
+	bool "USBAT/USBAT02-based storage support (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support storage devices
+	  based on the SCM/Shuttle USBAT/USBAT02 processors.
+
+	  Devices reported to work with this driver include:
+	  - CompactFlash reader included with Kodak DC3800 camera
+	  - Dane-Elec Zmate CompactFlash reader
+	  - Delkin Efilm reader2
+	  - HP 8200e/8210e/8230e CD-Writer Plus drives
+	  - I-JAM JS-50U
+	  - Jessops CompactFlash JESDCFRU BLACK
+	  - Kingston Technology PCREAD-USB/CF
+	  - Maxell UA4 CompactFlash reader
+	  - Memorex UCF-100
+	  - Microtech ZiO! ICS-45 CF2
+	  - RCA LYRA MP3 portable
+	  - Sandisk ImageMate SDDR-05b
+
+config USB_STORAGE_SDDR09
+	bool "SanDisk SDDR-09 (and other SmartMedia) support (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support the Sandisk SDDR-09
+	  SmartMedia reader in the USB Mass Storage driver.
+	  Also works for the Microtech Zio! SmartMedia reader.
+
+config USB_STORAGE_SDDR55
+	bool "SanDisk SDDR-55 SmartMedia support (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support the Sandisk SDDR-55
+	  SmartMedia reader in the USB Mass Storage driver.
+
+config USB_STORAGE_JUMPSHOT
+	bool "Lexar Jumpshot Compact Flash Reader (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support the Lexar Jumpshot
+	  USB CompactFlash reader.
+
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
new file mode 100644
index 0000000..56652cc
--- /dev/null
+++ b/drivers/usb/storage/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for the USB Mass Storage device drivers.
+#
+# 15 Aug 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+#
+
+EXTRA_CFLAGS	:= -Idrivers/scsi
+
+obj-$(CONFIG_USB_STORAGE)	+= usb-storage.o
+
+usb-storage-obj-$(CONFIG_USB_STORAGE_DEBUG)	+= debug.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_USBAT)	+= shuttle_usbat.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09)	+= sddr09.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55)	+= sddr55.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM)	+= freecom.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)	+= dpcm.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)	+= isd200.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)	+= datafab.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)	+= jumpshot.o
+
+usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
+			initializers.o $(usb-storage-obj-y)
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
new file mode 100644
index 0000000..54e3e6c7ec
--- /dev/null
+++ b/drivers/usb/storage/datafab.c
@@ -0,0 +1,669 @@
+/* Driver for Datafab USB Compact Flash reader
+ *
+ * $Id: datafab.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $
+ *
+ * datafab driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
+ *
+ *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *   which I used as a template for this driver.
+ *
+ *   Some bugfixes and scatter-gather code by Gregory P. Smith 
+ *   (greg-usb@electricrain.com)
+ *
+ *   Fix for media change by Joerg Schneider (js@joergschneider.com)
+ *
+ * Other contributors:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This driver attempts to support USB CompactFlash reader/writer devices
+ * based on Datafab USB-to-ATA chips.  It was specifically developed for the 
+ * Datafab MDCFE-B USB CompactFlash reader but has since been found to work 
+ * with a variety of Datafab-based devices from a number of manufacturers.
+ * I've received a report of this driver working with a Datafab-based
+ * SmartMedia device though please be aware that I'm personally unable to
+ * test SmartMedia support.
+ *
+ * This driver supports reading and writing.  If you're truly paranoid,
+ * however, you can force the driver into a write-protected state by setting
+ * the WP enable bits in datafab_handle_mode_sense().  See the comments
+ * in that routine.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "datafab.h"
+
+static int datafab_determine_lun(struct us_data *us,
+				 struct datafab_info *info);
+
+
+static inline int
+datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("datafab_bulk_read:  len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static inline int
+datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("datafab_bulk_write:  len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static int datafab_read_data(struct us_data *us,
+			     struct datafab_info *info,
+			     u32 sector,
+			     u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Datafab
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sectors > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		result = datafab_determine_lun(us, info);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+	}
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't read more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >> 8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 + (info->lun << 4);
+		command[5] |= (sector >> 24) & 0x0F;
+		command[6] = 0x20;
+		command[7] = 0x01;
+
+		// send the read command
+		result = datafab_bulk_write(us, command, 8);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result
+		result = datafab_bulk_read(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				 &sg_idx, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+
+static int datafab_write_data(struct us_data *us,
+			      struct datafab_info *info,
+			      u32 sector,
+			      u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *reply = us->iobuf;
+	unsigned char *buffer;
+	unsigned char thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Datafab
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sectors > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		result = datafab_determine_lun(us, info);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+	}
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't write more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg_idx, &sg_offset, FROM_XFER_BUF);
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >> 8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 + (info->lun << 4);
+		command[5] |= (sector >> 24) & 0x0F;
+		command[6] = 0x30;
+		command[7] = 0x02;
+
+		// send the command
+		result = datafab_bulk_write(us, command, 8);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// send the data
+		result = datafab_bulk_write(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result
+		result = datafab_bulk_read(us, reply, 2);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		if (reply[0] != 0x50 && reply[1] != 0) {
+			US_DEBUGP("datafab_write_data:  Gah! "
+				  "write return code: %02x %02x\n",
+				  reply[0], reply[1]);
+			result = USB_STOR_TRANSPORT_ERROR;
+			goto leave;
+		}
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+
+static int datafab_determine_lun(struct us_data *us,
+				 struct datafab_info *info)
+{
+	// Dual-slot readers can be thought of as dual-LUN devices.
+	// We need to determine which card slot is being used.
+	// We'll send an IDENTIFY DEVICE command and see which LUN responds...
+	//
+	// There might be a better way of doing this?
+
+	static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
+	unsigned char *command = us->iobuf;
+	unsigned char *buf;
+	int count = 0, rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	memcpy(command, scommand, 8);
+	buf = kmalloc(512, GFP_NOIO);
+	if (!buf)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("datafab_determine_lun:  locating...\n");
+
+	// we'll try 3 times before giving up...
+	//
+	while (count++ < 3) {
+		command[5] = 0xa0;
+
+		rc = datafab_bulk_write(us, command, 8);
+		if (rc != USB_STOR_XFER_GOOD) {
+			rc = USB_STOR_TRANSPORT_ERROR;
+			goto leave;
+		}
+
+		rc = datafab_bulk_read(us, buf, 512);
+		if (rc == USB_STOR_XFER_GOOD) {
+			info->lun = 0;
+			rc = USB_STOR_TRANSPORT_GOOD;
+			goto leave;
+		}
+
+		command[5] = 0xb0;
+
+		rc = datafab_bulk_write(us, command, 8);
+		if (rc != USB_STOR_XFER_GOOD) {
+			rc = USB_STOR_TRANSPORT_ERROR;
+			goto leave;
+		}
+
+		rc = datafab_bulk_read(us, buf, 512);
+		if (rc == USB_STOR_XFER_GOOD) {
+			info->lun = 1;
+			rc = USB_STOR_TRANSPORT_GOOD;
+			goto leave;
+		}
+
+		msleep(20);
+	}
+
+	rc = USB_STOR_TRANSPORT_ERROR;
+
+ leave:
+	kfree(buf);
+	return rc;
+}
+
+static int datafab_id_device(struct us_data *us,
+			     struct datafab_info *info)
+{
+	// this is a variation of the ATA "IDENTIFY DEVICE" command...according
+	// to the ATA spec, 'Sector Count' isn't used but the Windows driver
+	// sets this bit so we do too...
+	//
+	static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
+	unsigned char *command = us->iobuf;
+	unsigned char *reply;
+	int rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		rc = datafab_determine_lun(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+	}
+
+	memcpy(command, scommand, 8);
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	command[5] += (info->lun << 4);
+
+	rc = datafab_bulk_write(us, command, 8);
+	if (rc != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	// we'll go ahead and extract the media capacity while we're here...
+	//
+	rc = datafab_bulk_read(us, reply, 512);
+	if (rc == USB_STOR_XFER_GOOD) {
+		// capacity is at word offset 57-58
+		//
+		info->sectors = ((u32)(reply[117]) << 24) | 
+				((u32)(reply[116]) << 16) |
+				((u32)(reply[115]) <<  8) | 
+				((u32)(reply[114])      );
+		rc = USB_STOR_TRANSPORT_GOOD;
+		goto leave;
+	}
+
+	rc = USB_STOR_TRANSPORT_ERROR;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+
+static int datafab_handle_mode_sense(struct us_data *us,
+				     struct scsi_cmnd * srb, 
+				     int sense_6)
+{
+	static unsigned char rw_err_page[12] = {
+		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
+	};
+	static unsigned char cache_page[12] = {
+		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char rbac_page[12] = {
+		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char timer_page[8] = {
+		0x1C, 0x6, 0, 0, 0, 0
+	};
+	unsigned char pc, page_code;
+	unsigned int i = 0;
+	struct datafab_info *info = (struct datafab_info *) (us->extra);
+	unsigned char *ptr = us->iobuf;
+
+	// most of this stuff is just a hack to get things working.  the
+	// datafab reader doesn't present a SCSI interface so we
+	// fudge the SCSI commands...
+	//
+
+	pc = srb->cmnd[2] >> 6;
+	page_code = srb->cmnd[2] & 0x3F;
+
+	switch (pc) {
+	   case 0x0:
+		US_DEBUGP("datafab_handle_mode_sense:  Current values\n");
+		break;
+	   case 0x1:
+		US_DEBUGP("datafab_handle_mode_sense:  Changeable values\n");
+		break;
+	   case 0x2:
+		US_DEBUGP("datafab_handle_mode_sense:  Default values\n");
+		break;
+	   case 0x3:
+		US_DEBUGP("datafab_handle_mode_sense:  Saves values\n");
+		break;
+	}
+
+	memset(ptr, 0, 8);
+	if (sense_6) {
+		ptr[2] = 0x00;		// WP enable: 0x80
+		i = 4;
+	} else {
+		ptr[3] = 0x00;		// WP enable: 0x80
+		i = 8;
+	}
+
+	switch (page_code) {
+	   default:
+		// vendor-specific mode
+		info->sense_key = 0x05;
+		info->sense_asc = 0x24;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+
+	   case 0x1:
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+
+	   case 0x8:
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		break;
+
+	   case 0x1B:
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		break;
+
+	   case 0x1C:
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		break;
+
+	   case 0x3F:		// retrieve all pages
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+	}
+
+	if (sense_6)
+		ptr[0] = i - 1;
+	else
+		((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
+	usb_stor_set_xfer_buf(ptr, i, srb);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static void datafab_info_destructor(void *extra)
+{
+	// this routine is a placeholder...
+	// currently, we don't allocate any extra memory so we're okay
+}
+
+
+// Transport for the Datafab MDCFE-B
+//
+int datafab_transport(struct scsi_cmnd * srb, struct us_data *us)
+{
+	struct datafab_info *info;
+	int rc;
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_reply[8] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (!us->extra) {
+		us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
+		if (!us->extra) {
+			US_DEBUGP("datafab_transport:  Gah! "
+				  "Can't allocate storage for Datafab info struct!\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+		memset(us->extra, 0, sizeof(struct datafab_info));
+		us->extra_destructor = datafab_info_destructor;
+  		((struct datafab_info *)us->extra)->lun = -1;
+	}
+
+	info = (struct datafab_info *) (us->extra);
+
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("datafab_transport:  INQUIRY.  Returning bogus response");
+		memcpy(ptr, inquiry_reply, sizeof(inquiry_reply));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+		rc = datafab_id_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		US_DEBUGP("datafab_transport:  READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
+			  info->sectors, info->ssize);
+
+		// build the reply
+		// we need the last sector, not the number of sectors
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		US_DEBUGP("datafab_transport:  Gah! MODE_SELECT_10.\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	// don't bother implementing READ_6 or WRITE_6.
+	//
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("datafab_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// we'll probably never see a READ_12 but we'll do it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("datafab_transport:  READ_12: read block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("datafab_transport:  WRITE_10: write block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// we'll probably never see a WRITE_12 but we'll do it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("datafab_transport:  WRITE_12: write block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		US_DEBUGP("datafab_transport:  TEST_UNIT_READY.\n");
+		return datafab_id_device(us, info);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("datafab_transport:  REQUEST_SENSE.  Returning faked response\n");
+
+		// this response is pretty bogus right now.  eventually if necessary
+		// we can set the correct sense data.  so far though it hasn't been
+		// necessary
+		//
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+		US_DEBUGP("datafab_transport:  MODE_SENSE_6 detected\n");
+		return datafab_handle_mode_sense(us, srb, 1);
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		US_DEBUGP("datafab_transport:  MODE_SENSE_10 detected\n");
+		return datafab_handle_mode_sense(us, srb, 0);
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		// sure.  whatever.  not like we can stop the user from
+		// popping the media out of the device (no locking doors, etc)
+		//
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		/* this is used by sd.c'check_scsidisk_media_change to detect
+		   media change */
+		US_DEBUGP("datafab_transport:  START_STOP.\n");
+		/* the first datafab_id_device after a media change returns
+		   an error (determined experimentally) */
+		rc = datafab_id_device(us, info);
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->sense_key = NO_SENSE;
+			srb->result = SUCCESS;
+		} else {
+			info->sense_key = UNIT_ATTENTION;
+			srb->result = SAM_STAT_CHECK_CONDITION;
+		}
+		return rc;
+	}
+
+	US_DEBUGP("datafab_transport:  Gah! Unknown command: %d (0x%x)\n",
+		  srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
diff --git a/drivers/usb/storage/datafab.h b/drivers/usb/storage/datafab.h
new file mode 100644
index 0000000..32e3f27
--- /dev/null
+++ b/drivers/usb/storage/datafab.h
@@ -0,0 +1,40 @@
+/* Driver for Datafab MDCFE-B USB Compact Flash reader
+ * Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
+ *
+ * See datafab.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_DATAFAB_MDCFE_B_H
+#define _USB_DATAFAB_MDCFE_B_H
+
+extern int datafab_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+struct datafab_info {
+	unsigned long   sectors;	// total sector count
+	unsigned long   ssize;		// sector size in bytes
+	signed char	lun;		// used for dual-slot readers
+	
+	// the following aren't used yet
+	unsigned char   sense_key;
+	unsigned long   sense_asc;	// additional sense code
+	unsigned long   sense_ascq;	// additional sense code qualifier
+};
+
+#endif
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
new file mode 100644
index 0000000..d764837
--- /dev/null
+++ b/drivers/usb/storage/debug.c
@@ -0,0 +1,177 @@
+/* Driver for USB Mass Storage compliant devices
+ * Debugging Functions Source Code File
+ *
+ * $Id: debug.c,v 1.9 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/cdrom.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "debug.h"
+#include "scsi.h"
+
+
+void usb_stor_show_command(struct scsi_cmnd *srb)
+{
+	char *what = NULL;
+	int i;
+
+	switch (srb->cmnd[0]) {
+	case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break;
+	case REZERO_UNIT: what = "REZERO_UNIT"; break;
+	case REQUEST_SENSE: what = "REQUEST_SENSE"; break;
+	case FORMAT_UNIT: what = "FORMAT_UNIT"; break;
+	case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break;
+	case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break;
+	case READ_6: what = "READ_6"; break;
+	case WRITE_6: what = "WRITE_6"; break;
+	case SEEK_6: what = "SEEK_6"; break;
+	case READ_REVERSE: what = "READ_REVERSE"; break;
+	case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break;
+	case SPACE: what = "SPACE"; break;
+	case INQUIRY: what = "INQUIRY"; break;
+	case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break;
+	case MODE_SELECT: what = "MODE_SELECT"; break;
+	case RESERVE: what = "RESERVE"; break;
+	case RELEASE: what = "RELEASE"; break;
+	case COPY: what = "COPY"; break;
+	case ERASE: what = "ERASE"; break;
+	case MODE_SENSE: what = "MODE_SENSE"; break;
+	case START_STOP: what = "START_STOP"; break;
+	case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break;
+	case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break;
+	case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break;
+	case SET_WINDOW: what = "SET_WINDOW"; break;
+	case READ_CAPACITY: what = "READ_CAPACITY"; break;
+	case READ_10: what = "READ_10"; break;
+	case WRITE_10: what = "WRITE_10"; break;
+	case SEEK_10: what = "SEEK_10"; break;
+	case WRITE_VERIFY: what = "WRITE_VERIFY"; break;
+	case VERIFY: what = "VERIFY"; break;
+	case SEARCH_HIGH: what = "SEARCH_HIGH"; break;
+	case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break;
+	case SEARCH_LOW: what = "SEARCH_LOW"; break;
+	case SET_LIMITS: what = "SET_LIMITS"; break;
+	case READ_POSITION: what = "READ_POSITION"; break;
+	case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break;
+	case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break;
+	case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break;
+	case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break;
+	case COMPARE: what = "COMPARE"; break;
+	case COPY_VERIFY: what = "COPY_VERIFY"; break;
+	case WRITE_BUFFER: what = "WRITE_BUFFER"; break;
+	case READ_BUFFER: what = "READ_BUFFER"; break;
+	case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break;
+	case READ_LONG: what = "READ_LONG"; break;
+	case WRITE_LONG: what = "WRITE_LONG"; break;
+	case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break;
+	case WRITE_SAME: what = "WRITE_SAME"; break;
+	case GPCMD_READ_SUBCHANNEL: what = "READ SUBCHANNEL"; break;
+	case READ_TOC: what = "READ_TOC"; break;
+	case GPCMD_READ_HEADER: what = "READ HEADER"; break;
+	case GPCMD_PLAY_AUDIO_10: what = "PLAY AUDIO (10)"; break;
+	case GPCMD_PLAY_AUDIO_MSF: what = "PLAY AUDIO MSF"; break;
+	case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
+		what = "GET EVENT/STATUS NOTIFICATION"; break;
+	case GPCMD_PAUSE_RESUME: what = "PAUSE/RESUME"; break;
+	case LOG_SELECT: what = "LOG_SELECT"; break;
+	case LOG_SENSE: what = "LOG_SENSE"; break;
+	case GPCMD_STOP_PLAY_SCAN: what = "STOP PLAY/SCAN"; break;
+	case GPCMD_READ_DISC_INFO: what = "READ DISC INFORMATION"; break;
+	case GPCMD_READ_TRACK_RZONE_INFO:
+		what = "READ TRACK INFORMATION"; break;
+	case GPCMD_RESERVE_RZONE_TRACK: what = "RESERVE TRACK"; break;
+	case GPCMD_SEND_OPC: what = "SEND OPC"; break;
+	case MODE_SELECT_10: what = "MODE_SELECT_10"; break;
+	case GPCMD_REPAIR_RZONE_TRACK: what = "REPAIR TRACK"; break;
+	case 0x59: what = "READ MASTER CUE"; break;
+	case MODE_SENSE_10: what = "MODE_SENSE_10"; break;
+	case GPCMD_CLOSE_TRACK: what = "CLOSE TRACK/SESSION"; break;
+	case 0x5C: what = "READ BUFFER CAPACITY"; break;
+	case 0x5D: what = "SEND CUE SHEET"; break;
+	case GPCMD_BLANK: what = "BLANK"; break;
+	case MOVE_MEDIUM: what = "MOVE_MEDIUM or PLAY AUDIO (12)"; break;
+	case READ_12: what = "READ_12"; break;
+	case WRITE_12: what = "WRITE_12"; break;
+	case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break;
+	case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break;
+	case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break;
+	case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break;
+	case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break;
+	case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break;
+	case GPCMD_READ_CD_MSF: what = "READ CD MSF"; break;
+	case GPCMD_SCAN: what = "SCAN"; break;
+	case GPCMD_SET_SPEED: what = "SET CD SPEED"; break;
+	case GPCMD_MECHANISM_STATUS: what = "MECHANISM STATUS"; break;
+	case GPCMD_READ_CD: what = "READ CD"; break;
+	case 0xE1: what = "WRITE CONTINUE"; break;
+	case WRITE_LONG_2: what = "WRITE_LONG_2"; break;
+	default: what = "(unknown command)"; break;
+	}
+	US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
+	US_DEBUGP("");
+	for (i = 0; i < srb->cmd_len && i < 16; i++)
+		US_DEBUGPX(" %02x", srb->cmnd[i]);
+	US_DEBUGPX("\n");
+}
+
+void usb_stor_show_sense(
+		unsigned char key,
+		unsigned char asc,
+		unsigned char ascq) {
+
+	const char *what, *keystr;
+
+	keystr = scsi_sense_key_string(key);
+	what = scsi_extd_sense_format(asc, ascq);
+
+	if (keystr == NULL)
+		keystr = "(Unknown Key)";
+	if (what == NULL)
+		what = "(unknown ASC/ASCQ)";
+
+	US_DEBUGP("%s: ", keystr);
+	US_DEBUGPX(what, ascq);
+	US_DEBUGPX("\n");
+}
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
new file mode 100644
index 0000000..cd2096a
--- /dev/null
+++ b/drivers/usb/storage/debug.h
@@ -0,0 +1,65 @@
+/* Driver for USB Mass Storage compliant devices
+ * Debugging Functions Header File
+ *
+ * $Id: debug.h,v 1.6 2001/01/12 23:51:04 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#define USB_STORAGE "usb-storage: "
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+void usb_stor_show_command(struct scsi_cmnd *srb);
+void usb_stor_show_sense( unsigned char key,
+		unsigned char asc, unsigned char ascq );
+#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x )
+#define US_DEBUGPX(x...) printk( x )
+#define US_DEBUG(x) x 
+#else
+#define US_DEBUGP(x...)
+#define US_DEBUGPX(x...)
+#define US_DEBUG(x)
+#endif
+
+#endif
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
new file mode 100644
index 0000000..92b69e4
--- /dev/null
+++ b/drivers/usb/storage/dpcm.c
@@ -0,0 +1,89 @@
+/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
+ *
+ * $Id: dpcm.c,v 1.4 2001/06/11 02:54:25 mdharm Exp $
+ *
+ * DPCM driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Brian Webb (webbb@earthlink.net)
+ *
+ * This device contains both a CompactFlash card reader, which
+ * uses the Control/Bulk w/o Interrupt protocol and
+ * a SmartMedia card reader that uses the same protocol
+ * as the SDDR09.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "dpcm.h"
+#include "sddr09.h"
+
+/*
+ * Transport for the Microtech DPCM-USB
+ *
+ */
+int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+  int ret;
+
+  if(srb == NULL)
+    return USB_STOR_TRANSPORT_ERROR;
+
+  US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+
+  switch(srb->device->lun) {
+  case 0:
+
+    /*
+     * LUN 0 corresponds to the CompactFlash card reader.
+     */
+    ret = usb_stor_CB_transport(srb, us);
+    break;
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+  case 1:
+
+    /*
+     * LUN 1 corresponds to the SmartMedia card reader.
+     */
+
+    /*
+     * Set the LUN to 0 (just in case).
+     */
+    srb->device->lun = 0; us->srb->device->lun = 0;
+    ret = sddr09_transport(srb, us);
+    srb->device->lun = 1; us->srb->device->lun = 1;
+    break;
+
+#endif
+
+  default:
+    US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+    ret = USB_STOR_TRANSPORT_ERROR;
+    break;
+  }
+  return ret;
+}
diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h
new file mode 100644
index 0000000..81b464c
--- /dev/null
+++ b/drivers/usb/storage/dpcm.h
@@ -0,0 +1,34 @@
+/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
+ *
+ * $Id: dpcm.h,v 1.2 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * DPCM driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Brian Webb (webbb@earthlink.net)
+ *
+ * See dpcm.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MICROTECH_DPCM_USB_H
+#define _MICROTECH_DPCM_USB_H
+
+extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
new file mode 100644
index 0000000..30e9605
--- /dev/null
+++ b/drivers/usb/storage/freecom.c
@@ -0,0 +1,488 @@
+/* Driver for Freecom USB/IDE adaptor
+ *
+ * $Id: freecom.c,v 1.22 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Freecom v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (C) 2000 David Brown <usb-storage@davidb.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver was developed with information provided in FREECOM's USB
+ * Programmers Reference Guide.  For further information contact Freecom
+ * (http://www.freecom.de/)
+ */
+
+#include <linux/config.h>
+#include <linux/hdreg.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "freecom.h"
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void pdump (void *, int);
+#endif
+
+/* Bits of HD_STATUS */
+#define ERR_STAT		0x01
+#define DRQ_STAT		0x08
+
+/* All of the outgoing packets are 64 bytes long. */
+struct freecom_cb_wrap {
+	u8    Type;		/* Command type. */
+	u8    Timeout;		/* Timeout in seconds. */
+	u8    Atapi[12];	/* An ATAPI packet. */
+	u8    Filler[50];	/* Padding Data. */
+};
+
+struct freecom_xfer_wrap {
+	u8    Type;		/* Command type. */
+	u8    Timeout;		/* Timeout in seconds. */
+	__le32   Count;		/* Number of bytes to transfer. */
+	u8    Pad[58];
+} __attribute__ ((packed));
+
+struct freecom_ide_out {
+	u8    Type;		/* Type + IDE register. */
+	u8    Pad;
+	__le16   Value;		/* Value to write. */
+	u8    Pad2[60];
+};
+
+struct freecom_ide_in {
+	u8    Type;		/* Type | IDE register. */
+	u8    Pad[63];
+};
+
+struct freecom_status {
+	u8    Status;
+	u8    Reason;
+	__le16   Count;
+	u8    Pad[60];
+};
+
+/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
+ * register. */
+#define FCM_INT_STATUS		0x02 /* INDEX_STAT */
+#define FCM_STATUS_BUSY		0x80
+
+/* These are the packet types.  The low bit indicates that this command
+ * should wait for an interrupt. */
+#define FCM_PACKET_ATAPI	0x21
+#define FCM_PACKET_STATUS	0x20
+
+/* Receive data from the IDE interface.  The ATAPI packet has already
+ * waited, so the data should be immediately available. */
+#define FCM_PACKET_INPUT	0x81
+
+/* Send data to the IDE interface. */
+#define FCM_PACKET_OUTPUT	0x01
+
+/* Write a value to an ide register.  Or the ide register to write after
+ * munging the address a bit. */
+#define FCM_PACKET_IDE_WRITE	0x40
+#define FCM_PACKET_IDE_READ	0xC0
+
+/* All packets (except for status) are 64 bytes long. */
+#define FCM_PACKET_LENGTH		64
+#define FCM_STATUS_PACKET_LENGTH	4
+
+static int
+freecom_readdata (struct scsi_cmnd *srb, struct us_data *us,
+		unsigned int ipipe, unsigned int opipe, int count)
+{
+	struct freecom_xfer_wrap *fxfr =
+		(struct freecom_xfer_wrap *) us->iobuf;
+	int result;
+
+	fxfr->Type = FCM_PACKET_INPUT | 0x00;
+	fxfr->Timeout = 0;    /* Short timeout for debugging. */
+	fxfr->Count = cpu_to_le32 (count);
+	memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
+
+	US_DEBUGP("Read data Freecom! (c=%d)\n", count);
+
+	/* Issue the transfer command. */
+	result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
+			FCM_PACKET_LENGTH, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP ("Freecom readdata transport error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Now transfer all of our blocks. */
+	US_DEBUGP("Start of read\n");
+	result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
+			count, srb->use_sg, &srb->resid);
+	US_DEBUGP("freecom_readdata done!\n");
+
+	if (result > USB_STOR_XFER_SHORT)
+		return USB_STOR_TRANSPORT_ERROR;
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int
+freecom_writedata (struct scsi_cmnd *srb, struct us_data *us,
+		int unsigned ipipe, unsigned int opipe, int count)
+{
+	struct freecom_xfer_wrap *fxfr =
+		(struct freecom_xfer_wrap *) us->iobuf;
+	int result;
+
+	fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
+	fxfr->Timeout = 0;    /* Short timeout for debugging. */
+	fxfr->Count = cpu_to_le32 (count);
+	memset (fxfr->Pad, 0, sizeof (fxfr->Pad));
+
+	US_DEBUGP("Write data Freecom! (c=%d)\n", count);
+
+	/* Issue the transfer command. */
+	result = usb_stor_bulk_transfer_buf (us, opipe, fxfr,
+			FCM_PACKET_LENGTH, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP ("Freecom writedata transport error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Now transfer all of our blocks. */
+	US_DEBUGP("Start of write\n");
+	result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
+			count, srb->use_sg, &srb->resid);
+
+	US_DEBUGP("freecom_writedata done!\n");
+	if (result > USB_STOR_XFER_SHORT)
+		return USB_STOR_TRANSPORT_ERROR;
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Transport for the Freecom USB/IDE adaptor.
+ *
+ */
+int freecom_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct freecom_cb_wrap *fcb;
+	struct freecom_status  *fst;
+	unsigned int ipipe, opipe;		/* We need both pipes. */
+	int result;
+	unsigned int partial;
+	int length;
+
+	fcb = (struct freecom_cb_wrap *) us->iobuf;
+	fst = (struct freecom_status *) us->iobuf;
+
+	US_DEBUGP("Freecom TRANSPORT STARTED\n");
+
+	/* Get handles for both transports. */
+	opipe = us->send_bulk_pipe;
+	ipipe = us->recv_bulk_pipe;
+
+	/* The ATAPI Command always goes out first. */
+	fcb->Type = FCM_PACKET_ATAPI | 0x00;
+	fcb->Timeout = 0;
+	memcpy (fcb->Atapi, srb->cmnd, 12);
+	memset (fcb->Filler, 0, sizeof (fcb->Filler));
+
+	US_DEBUG(pdump (srb->cmnd, 12));
+
+	/* Send it out. */
+	result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
+			FCM_PACKET_LENGTH, NULL);
+
+	/* The Freecom device will only fail if there is something wrong in
+	 * USB land.  It returns the status in its own registers, which
+	 * come back in the bulk pipe. */
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP ("freecom transport error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* There are times we can optimize out this status read, but it
+	 * doesn't hurt us to always do it now. */
+	result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+			FCM_STATUS_PACKET_LENGTH, &partial);
+	US_DEBUGP("foo Status result %d %u\n", result, partial);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUG(pdump ((void *) fst, partial));
+
+	/* The firmware will time-out commands after 20 seconds. Some commands
+	 * can legitimately take longer than this, so we use a different
+	 * command that only waits for the interrupt and then sends status,
+	 * without having to send a new ATAPI command to the device. 
+	 *
+	 * NOTE: There is some indication that a data transfer after a timeout
+	 * may not work, but that is a condition that should never happen.
+	 */
+	while (fst->Status & FCM_STATUS_BUSY) {
+		US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n");
+		US_DEBUGP("fst->Status is %x\n", fst->Status);
+
+		/* Get the status again */
+		fcb->Type = FCM_PACKET_STATUS;
+		fcb->Timeout = 0;
+		memset (fcb->Atapi, 0, sizeof(fcb->Atapi));
+		memset (fcb->Filler, 0, sizeof (fcb->Filler));
+
+		/* Send it out. */
+		result = usb_stor_bulk_transfer_buf (us, opipe, fcb,
+				FCM_PACKET_LENGTH, NULL);
+
+		/* The Freecom device will only fail if there is something
+		 * wrong in USB land.  It returns the status in its own
+		 * registers, which come back in the bulk pipe.
+		 */
+		if (result != USB_STOR_XFER_GOOD) {
+			US_DEBUGP ("freecom transport error\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		/* get the data */
+		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+				FCM_STATUS_PACKET_LENGTH, &partial);
+
+		US_DEBUGP("bar Status result %d %u\n", result, partial);
+		if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		US_DEBUG(pdump ((void *) fst, partial));
+	}
+
+	if (partial != 4)
+		return USB_STOR_TRANSPORT_ERROR;
+	if ((fst->Status & 1) != 0) {
+		US_DEBUGP("operation failed\n");
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* The device might not have as much data available as we
+	 * requested.  If you ask for more than the device has, this reads
+	 * and such will hang. */
+	US_DEBUGP("Device indicates that it has %d bytes available\n",
+			le16_to_cpu (fst->Count));
+	US_DEBUGP("SCSI requested %d\n", srb->request_bufflen);
+
+	/* Find the length we desire to read. */
+	switch (srb->cmnd[0]) {
+		case INQUIRY:
+		case REQUEST_SENSE:		/* 16 or 18 bytes? spec says 18, lots of devices only have 16 */
+		case MODE_SENSE:
+		case MODE_SENSE_10:
+			length = le16_to_cpu(fst->Count);
+			break;
+		default:
+ 			length = srb->request_bufflen;
+	}
+
+	/* verify that this amount is legal */
+	if (length > srb->request_bufflen) {
+		length = srb->request_bufflen;
+		US_DEBUGP("Truncating request to match buffer length: %d\n", length);
+	}
+
+	/* What we do now depends on what direction the data is supposed to
+	 * move in. */
+
+	switch (us->srb->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+		/* catch bogus "read 0 length" case */
+		if (!length)
+			break;
+		/* Make sure that the status indicates that the device
+		 * wants data as well. */
+		if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) {
+			US_DEBUGP("SCSI wants data, drive doesn't have any\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		result = freecom_readdata (srb, us, ipipe, opipe, length);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+
+		US_DEBUGP("FCM: Waiting for status\n");
+		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+				FCM_PACKET_LENGTH, &partial);
+		US_DEBUG(pdump ((void *) fst, partial));
+
+		if (partial != 4 || result > USB_STOR_XFER_SHORT)
+			return USB_STOR_TRANSPORT_ERROR;
+		if ((fst->Status & ERR_STAT) != 0) {
+			US_DEBUGP("operation failed\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		if ((fst->Reason & 3) != 3) {
+			US_DEBUGP("Drive seems still hungry\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		US_DEBUGP("Transfer happy\n");
+		break;
+
+	case DMA_TO_DEVICE:
+		/* catch bogus "write 0 length" case */
+		if (!length)
+			break;
+		/* Make sure the status indicates that the device wants to
+		 * send us data. */
+		/* !!IMPLEMENT!! */
+		result = freecom_writedata (srb, us, ipipe, opipe, length);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			return result;
+
+		US_DEBUGP("FCM: Waiting for status\n");
+		result = usb_stor_bulk_transfer_buf (us, ipipe, fst,
+				FCM_PACKET_LENGTH, &partial);
+
+		if (partial != 4 || result > USB_STOR_XFER_SHORT)
+			return USB_STOR_TRANSPORT_ERROR;
+		if ((fst->Status & ERR_STAT) != 0) {
+			US_DEBUGP("operation failed\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		if ((fst->Reason & 3) != 3) {
+			US_DEBUGP("Drive seems still hungry\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		US_DEBUGP("Transfer happy\n");
+		break;
+
+
+	case DMA_NONE:
+		/* Easy, do nothing. */
+		break;
+
+	default:
+		/* should never hit here -- filtered in usb.c */
+		US_DEBUGP ("freecom unimplemented direction: %d\n",
+				us->srb->sc_data_direction);
+		// Return fail, SCSI seems to handle this better.
+		return USB_STOR_TRANSPORT_FAILED;
+		break;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+int
+freecom_init (struct us_data *us)
+{
+	int result;
+	char *buffer = us->iobuf;
+
+	/* The DMA-mapped I/O buffer is 64 bytes long, just right for
+	 * all our packets.  No need to allocate any extra buffer space.
+	 */
+
+	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+			0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
+	buffer[32] = '\0';
+	US_DEBUGP("String returned from FC init is: %s\n", buffer);
+
+	/* Special thanks to the people at Freecom for providing me with
+	 * this "magic sequence", which they use in their Windows and MacOS
+	 * drivers to make sure that all the attached perhiperals are
+	 * properly reset.
+	 */
+
+	/* send reset */
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
+	US_DEBUGP("result from activate reset is %d\n", result);
+
+	/* wait 250ms */
+	mdelay(250);
+
+	/* clear reset */
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
+	US_DEBUGP("result from clear reset is %d\n", result);
+
+	/* wait 3 seconds */
+	mdelay(3 * 1000);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+int usb_stor_freecom_reset(struct us_data *us)
+{
+	printk (KERN_CRIT "freecom reset called\n");
+
+	/* We don't really have this feature. */
+	return FAILED;
+}
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void pdump (void *ibuffer, int length)
+{
+	static char line[80];
+	int offset = 0;
+	unsigned char *buffer = (unsigned char *) ibuffer;
+	int i, j;
+	int from, base;
+
+	offset = 0;
+	for (i = 0; i < length; i++) {
+		if ((i & 15) == 0) {
+			if (i > 0) {
+				offset += sprintf (line+offset, " - ");
+				for (j = i - 16; j < i; j++) {
+					if (buffer[j] >= 32 && buffer[j] <= 126)
+						line[offset++] = buffer[j];
+					else
+						line[offset++] = '.';
+				}
+				line[offset] = 0;
+				US_DEBUGP("%s\n", line);
+				offset = 0;
+			}
+			offset += sprintf (line+offset, "%08x:", i);
+		}
+		else if ((i & 7) == 0) {
+			offset += sprintf (line+offset, " -");
+		}
+		offset += sprintf (line+offset, " %02x", buffer[i] & 0xff);
+	}
+
+	/* Add the last "chunk" of data. */
+	from = (length - 1) % 16;
+	base = ((length - 1) / 16) * 16;
+
+	for (i = from + 1; i < 16; i++)
+		offset += sprintf (line+offset, "   ");
+	if (from < 8)
+		offset += sprintf (line+offset, "  ");
+	offset += sprintf (line+offset, " - ");
+
+	for (i = 0; i <= from; i++) {
+		if (buffer[base+i] >= 32 && buffer[base+i] <= 126)
+			line[offset++] = buffer[base+i];
+		else
+			line[offset++] = '.';
+	}
+	line[offset] = 0;
+	US_DEBUGP("%s\n", line);
+	offset = 0;
+}
+#endif
+
diff --git a/drivers/usb/storage/freecom.h b/drivers/usb/storage/freecom.h
new file mode 100644
index 0000000..1b012d6
--- /dev/null
+++ b/drivers/usb/storage/freecom.h
@@ -0,0 +1,36 @@
+/* Driver for Freecom USB/IDE adaptor
+ *
+ * $Id: freecom.h,v 1.4 2000/08/29 14:49:15 dlbrown Exp $
+ *
+ * Freecom v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 David Brown <usb-storage@davidb.org>
+ *
+ * See freecom.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FREECOM_USB_H
+#define _FREECOM_USB_H
+
+extern int freecom_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int usb_stor_freecom_reset(struct us_data *us);
+extern int freecom_init (struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
new file mode 100644
index 0000000..5b06f92
--- /dev/null
+++ b/drivers/usb/storage/initializers.c
@@ -0,0 +1,93 @@
+/* Special Initializers for certain USB Mass Storage devices
+ *
+ * $Id: initializers.c,v 1.2 2000/09/06 22:35:57 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+
+#include "usb.h"
+#include "initializers.h"
+#include "debug.h"
+#include "transport.h"
+
+/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
+ * mode */
+int usb_stor_euscsi_init(struct us_data *us)
+{
+	int result;
+
+	US_DEBUGP("Attempting to init eUSCSI bridge...\n");
+	us->iobuf[0] = 0x1;
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
+			0x01, 0x0, us->iobuf, 0x1, 5*HZ);
+	US_DEBUGP("-- result is %d\n", result);
+
+	return 0;
+}
+
+/* This function is required to activate all four slots on the UCR-61S2B
+ * flash reader */
+int usb_stor_ucr61s2b_init(struct us_data *us)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
+	int res, partial;
+	static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS";
+
+	US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
+
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->Tag = 0;
+	bcb->DataTransferLength = cpu_to_le32(0);
+	bcb->Flags = bcb->Lun = 0;
+	bcb->Length = sizeof(init_string) - 1;
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, init_string, sizeof(init_string) - 1);
+
+	res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
+			US_BULK_CB_WRAP_LEN, &partial);
+	if(res)
+		return res;
+
+	US_DEBUGP("Getting status packet...\n");
+	res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+			US_BULK_CS_WRAP_LEN, &partial);
+
+	return (res ? -1 : 0);
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
new file mode 100644
index 0000000..7372386
--- /dev/null
+++ b/drivers/usb/storage/initializers.h
@@ -0,0 +1,54 @@
+/* Header file for Special Initializers for certain USB Mass Storage devices
+ *
+ * $Id: initializers.h,v 1.1 2000/08/29 23:07:02 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include "usb.h"
+#include "transport.h"
+
+/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
+ * mode */
+int usb_stor_euscsi_init(struct us_data *us);
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+int sddr09_init(struct us_data *us);
+#endif
+
+/* This function is required to activate all four slots on the UCR-61S2B
+ * flash reader */
+int usb_stor_ucr61s2b_init(struct us_data *us);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
new file mode 100644
index 0000000..ecb328a
--- /dev/null
+++ b/drivers/usb/storage/isd200.c
@@ -0,0 +1,1442 @@
+/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
+ *
+ * $Id: isd200.c,v 1.16 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance:
+ *   (C) 2001-2002 Björn Stenberg (bjorn@haxx.se)
+ *
+ * Developed with the assistance of:
+ *   (C) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work:
+ *   (C) 2000 In-System Design, Inc. (support@in-system.com)
+ *
+ * The ISD200 ASIC does not natively support ATA devices.  The chip
+ * does implement an interface, the ATA Command Block (ATACB) which provides
+ * a means of passing ATA commands and ATA register accesses to a device.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * History:
+ *
+ *  2002-10-19: Removed the specialized transfer routines.
+ *		(Alan Stern <stern@rowland.harvard.edu>)
+ *  2001-02-24: Removed lots of duplicate code and simplified the structure.
+ *	      (bjorn@haxx.se)
+ *  2002-01-16: Fixed endianness bug so it works on the ppc arch.
+ *	      (Luc Saillard <luc@saillard.org>)
+ *  2002-01-17: All bitfields removed.
+ *	      (bjorn@haxx.se)
+ */
+
+
+/* Include files */
+
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+#include "isd200.h"
+
+
+/* Timeout defines (in Seconds) */
+
+#define ISD200_ENUM_BSY_TIMEOUT		35
+#define ISD200_ENUM_DETECT_TIMEOUT      30
+#define ISD200_DEFAULT_TIMEOUT		30
+
+/* device flags */
+#define DF_ATA_DEVICE		0x0001
+#define DF_MEDIA_STATUS_ENABLED	0x0002
+#define DF_REMOVABLE_MEDIA	0x0004
+
+/* capability bit definitions */
+#define CAPABILITY_DMA		0x01
+#define CAPABILITY_LBA		0x02
+
+/* command_setX bit definitions */
+#define COMMANDSET_REMOVABLE	0x02
+#define COMMANDSET_MEDIA_STATUS 0x10
+
+/* ATA Vendor Specific defines */
+#define ATA_ADDRESS_DEVHEAD_STD      0xa0
+#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40    
+#define ATA_ADDRESS_DEVHEAD_SLAVE    0x10
+
+/* Action Select bits */
+#define ACTION_SELECT_0	     0x01
+#define ACTION_SELECT_1	     0x02
+#define ACTION_SELECT_2	     0x04
+#define ACTION_SELECT_3	     0x08
+#define ACTION_SELECT_4	     0x10
+#define ACTION_SELECT_5	     0x20
+#define ACTION_SELECT_6	     0x40
+#define ACTION_SELECT_7	     0x80
+
+/* Register Select bits */
+#define REG_ALTERNATE_STATUS	0x01
+#define REG_DEVICE_CONTROL	0x01
+#define REG_ERROR		0x02
+#define REG_FEATURES		0x02
+#define REG_SECTOR_COUNT	0x04
+#define REG_SECTOR_NUMBER	0x08
+#define REG_CYLINDER_LOW	0x10
+#define REG_CYLINDER_HIGH	0x20
+#define REG_DEVICE_HEAD		0x40
+#define REG_STATUS		0x80
+#define REG_COMMAND		0x80
+
+/* ATA error definitions not in <linux/hdreg.h> */
+#define ATA_ERROR_MEDIA_CHANGE		0x20
+
+/* ATA command definitions not in <linux/hdreg.h> */
+#define ATA_COMMAND_GET_MEDIA_STATUS	0xDA
+#define ATA_COMMAND_MEDIA_EJECT		0xED
+
+/* ATA drive control definitions */
+#define ATA_DC_DISABLE_INTERRUPTS	0x02
+#define ATA_DC_RESET_CONTROLLER		0x04
+#define ATA_DC_REENABLE_CONTROLLER	0x00
+
+/*
+ *  General purpose return codes
+ */ 
+
+#define ISD200_ERROR		-1
+#define ISD200_GOOD		 0
+
+/*
+ * Transport return codes
+ */
+
+#define ISD200_TRANSPORT_GOOD       0   /* Transport good, command good     */
+#define ISD200_TRANSPORT_FAILED     1   /* Transport good, command failed   */
+#define ISD200_TRANSPORT_ERROR      2   /* Transport bad (i.e. device dead) */
+
+/* driver action codes */
+#define	ACTION_READ_STATUS	0
+#define	ACTION_RESET		1
+#define	ACTION_REENABLE		2
+#define	ACTION_SOFT_RESET	3
+#define	ACTION_ENUM		4
+#define	ACTION_IDENTIFY		5
+
+
+/*
+ * ata_cdb struct
+ */
+
+
+union ata_cdb {
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char WriteData3F6;
+		unsigned char WriteData1F1;
+		unsigned char WriteData1F2;
+		unsigned char WriteData1F3;
+		unsigned char WriteData1F4;
+		unsigned char WriteData1F5;
+		unsigned char WriteData1F6;
+		unsigned char WriteData1F7;
+		unsigned char Reserved[3];
+	} generic;
+
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char AlternateStatusByte;
+		unsigned char ErrorByte;
+		unsigned char SectorCountByte;
+		unsigned char SectorNumberByte;
+		unsigned char CylinderLowByte;
+		unsigned char CylinderHighByte;
+		unsigned char DeviceHeadByte;
+		unsigned char StatusByte;
+		unsigned char Reserved[3];
+	} read;
+
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char DeviceControlByte;
+		unsigned char FeaturesByte;
+		unsigned char SectorCountByte;
+		unsigned char SectorNumberByte;
+		unsigned char CylinderLowByte;
+		unsigned char CylinderHighByte;
+		unsigned char DeviceHeadByte;
+		unsigned char CommandByte;
+		unsigned char Reserved[3];
+	} write;
+};
+
+
+/*
+ * Inquiry data structure. This is the data returned from the target
+ * after it receives an inquiry.
+ *
+ * This structure may be extended by the number of bytes specified
+ * in the field AdditionalLength. The defined size constant only
+ * includes fields through ProductRevisionLevel.
+ */
+
+/*
+ * DeviceType field
+ */
+#define DIRECT_ACCESS_DEVICE	    0x00    /* disks */
+#define DEVICE_REMOVABLE		0x80
+
+struct inquiry_data {
+   	unsigned char DeviceType;
+	unsigned char DeviceTypeModifier;
+	unsigned char Versions;
+	unsigned char Format; 
+	unsigned char AdditionalLength;
+	unsigned char Reserved[2];
+	unsigned char Capability;
+	unsigned char VendorId[8];
+	unsigned char ProductId[16];
+	unsigned char ProductRevisionLevel[4];
+	unsigned char VendorSpecific[20];
+	unsigned char Reserved3[40];
+} __attribute__ ((packed));
+
+/*
+ * INQUIRY data buffer size
+ */
+
+#define INQUIRYDATABUFFERSIZE 36
+
+
+/*
+ * ISD200 CONFIG data struct
+ */
+
+#define ATACFG_TIMING	  0x0f
+#define ATACFG_ATAPI_RESET     0x10
+#define ATACFG_MASTER	  0x20
+#define ATACFG_BLOCKSIZE       0xa0
+
+#define ATACFGE_LAST_LUN       0x07
+#define ATACFGE_DESC_OVERRIDE  0x08
+#define ATACFGE_STATE_SUSPEND  0x10
+#define ATACFGE_SKIP_BOOT      0x20
+#define ATACFGE_CONF_DESC2     0x40
+#define ATACFGE_INIT_STATUS    0x80
+
+#define CFG_CAPABILITY_SRST    0x01
+
+struct isd200_config {
+	unsigned char EventNotification;
+	unsigned char ExternalClock;
+	unsigned char ATAInitTimeout;
+	unsigned char ATAConfig;
+	unsigned char ATAMajorCommand;
+	unsigned char ATAMinorCommand;
+	unsigned char ATAExtraConfig;
+	unsigned char Capability;
+}__attribute__ ((packed));
+
+
+/*
+ * ISD200 driver information struct
+ */
+
+struct isd200_info {
+	struct inquiry_data InquiryData;
+	struct hd_driveid *id;
+	struct isd200_config ConfigData;
+	unsigned char *RegsBuf;
+	unsigned char ATARegs[8];
+	unsigned char DeviceHead;
+	unsigned char DeviceFlags;
+
+	/* maximum number of LUNs supported */
+	unsigned char MaxLUNs;
+	struct scsi_cmnd srb;
+};
+
+
+/*
+ * Read Capacity Data - returned in Big Endian format
+ */
+
+struct read_capacity_data {
+	__be32 LogicalBlockAddress;
+	__be32 BytesPerBlock;
+};
+
+/*
+ * Read Block Limits Data - returned in Big Endian format
+ * This structure returns the maximum and minimum block
+ * size for a TAPE device.
+ */
+
+struct read_block_limits {
+	unsigned char Reserved;
+	unsigned char BlockMaximumSize[3];
+	unsigned char BlockMinimumSize[2];
+};
+
+
+/*
+ * Sense Data Format
+ */
+
+#define SENSE_ERRCODE	   0x7f
+#define SENSE_ERRCODE_VALID     0x80
+#define SENSE_FLAG_SENSE_KEY    0x0f
+#define SENSE_FLAG_BAD_LENGTH   0x20
+#define SENSE_FLAG_END_OF_MEDIA 0x40
+#define SENSE_FLAG_FILE_MARK    0x80
+struct sense_data {
+	unsigned char ErrorCode;
+	unsigned char SegmentNumber;
+	unsigned char Flags;
+	unsigned char Information[4];
+	unsigned char AdditionalSenseLength;
+	unsigned char CommandSpecificInformation[4];
+	unsigned char AdditionalSenseCode;
+	unsigned char AdditionalSenseCodeQualifier;
+	unsigned char FieldReplaceableUnitCode;
+	unsigned char SenseKeySpecific[3];
+} __attribute__ ((packed));
+
+/*
+ * Default request sense buffer size
+ */
+
+#define SENSE_BUFFER_SIZE 18
+
+/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/**************************************************************************
+ * isd200_build_sense
+ *									 
+ *  Builds an artificial sense buffer to report the results of a 
+ *  failed command.
+ *								       
+ * RETURNS:
+ *    void
+ */
+static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
+	unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
+
+	if(error & ATA_ERROR_MEDIA_CHANGE) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags = UNIT_ATTENTION;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else if(error & MCR_ERR) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags =  UNIT_ATTENTION;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else if(error & TRK0_ERR) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags =  NOT_READY;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else if(error & ECC_ERR) {
+		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
+		buf->AdditionalSenseLength = 0xb;
+		buf->Flags =  DATA_PROTECT;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	} else {
+		buf->ErrorCode = 0;
+		buf->AdditionalSenseLength = 0;
+		buf->Flags =  0;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+	}
+}
+
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+
+/**************************************************************************
+ *  isd200_action
+ *
+ * Routine for sending commands to the isd200
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_action( struct us_data *us, int action, 
+			  void* pointer, int value )
+{
+	union ata_cdb ata;
+	struct scsi_device srb_dev;
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	struct scsi_cmnd *srb = &info->srb;
+	int status;
+
+	memset(&ata, 0, sizeof(ata));
+	memset(&srb_dev, 0, sizeof(srb_dev));
+	srb->device = &srb_dev;
+	++srb->serial_number;
+
+	ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+	ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+	ata.generic.TransferBlockSize = 1;
+
+	switch ( action ) {
+	case ACTION_READ_STATUS:
+		US_DEBUGP("   isd200_action(READ_STATUS)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
+		ata.generic.RegisterSelect =
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_STATUS | REG_ERROR;
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+		srb->request_buffer = pointer;
+		srb->request_bufflen = value;
+		break;
+
+	case ACTION_ENUM:
+		US_DEBUGP("   isd200_action(ENUM,0x%02x)\n",value);
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+					   ACTION_SELECT_3|ACTION_SELECT_4|
+					   ACTION_SELECT_5;
+		ata.generic.RegisterSelect = REG_DEVICE_HEAD;
+		ata.write.DeviceHeadByte = value;
+		srb->sc_data_direction = DMA_NONE;
+		break;
+
+	case ACTION_RESET:
+		US_DEBUGP("   isd200_action(RESET)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+					   ACTION_SELECT_3|ACTION_SELECT_4;
+		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
+		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
+		srb->sc_data_direction = DMA_NONE;
+		break;
+
+	case ACTION_REENABLE:
+		US_DEBUGP("   isd200_action(REENABLE)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+					   ACTION_SELECT_3|ACTION_SELECT_4;
+		ata.generic.RegisterSelect = REG_DEVICE_CONTROL;
+		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
+		srb->sc_data_direction = DMA_NONE;
+		break;
+
+	case ACTION_SOFT_RESET:
+		US_DEBUGP("   isd200_action(SOFT_RESET)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
+		ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND;
+		ata.write.DeviceHeadByte = info->DeviceHead;
+		ata.write.CommandByte = WIN_SRST;
+		srb->sc_data_direction = DMA_NONE;
+		break;
+
+	case ACTION_IDENTIFY:
+		US_DEBUGP("   isd200_action(IDENTIFY)\n");
+		ata.generic.RegisterSelect = REG_COMMAND;
+		ata.write.CommandByte = WIN_IDENTIFY;
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+		srb->request_buffer = (void *) info->id;
+		srb->request_bufflen = sizeof(struct hd_driveid);
+		break;
+
+	default:
+		US_DEBUGP("Error: Undefined action %d\n",action);
+		break;
+	}
+
+	memcpy(srb->cmnd, &ata, sizeof(ata.generic));
+	srb->cmd_len = sizeof(ata.generic);
+	status = usb_stor_Bulk_transport(srb, us);
+	if (status == USB_STOR_TRANSPORT_GOOD)
+		status = ISD200_GOOD;
+	else {
+		US_DEBUGP("   isd200_action(0x%02x) error: %d\n",action,status);
+		status = ISD200_ERROR;
+		/* need to reset device here */
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * isd200_read_regs
+ *									 
+ * Read ATA Registers
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_read_regs( struct us_data *us )
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering isd200_IssueATAReadRegs\n");
+
+	transferStatus = isd200_action( us, ACTION_READ_STATUS,
+				    info->RegsBuf, sizeof(info->ATARegs) );
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error reading ATA registers\n");
+		retStatus = ISD200_ERROR;
+	} else {
+		memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs));
+		US_DEBUGP("   Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", 
+			  info->ATARegs[IDE_ERROR_OFFSET]);
+	}
+
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and receive the response.
+ */
+static void isd200_invoke_transport( struct us_data *us, 
+			      struct scsi_cmnd *srb, 
+			      union ata_cdb *ataCdb )
+{
+	int need_auto_sense = 0;
+	int transferStatus;
+	int result;
+
+	/* send the command to the transport layer */
+	memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic));
+	srb->cmd_len = sizeof(ataCdb->generic);
+	transferStatus = usb_stor_Bulk_transport(srb, us);
+
+	/* if the command gets aborted by the higher layers, we need to
+	 * short-circuit all other processing
+	 */
+	if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+		US_DEBUGP("-- command was aborted\n");
+		goto Handle_Abort;
+	}
+
+	switch (transferStatus) {
+
+	case USB_STOR_TRANSPORT_GOOD:
+		/* Indicate a good result */
+		srb->result = SAM_STAT_GOOD;
+		break;
+
+	case USB_STOR_TRANSPORT_NO_SENSE:
+		US_DEBUGP("-- transport indicates protocol failure\n");
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		return;
+
+	case USB_STOR_TRANSPORT_FAILED:
+		US_DEBUGP("-- transport indicates command failure\n");
+		need_auto_sense = 1;
+		break;
+
+	case USB_STOR_TRANSPORT_ERROR:
+		US_DEBUGP("-- transport indicates transport error\n");
+		srb->result = DID_ERROR << 16;
+		/* Need reset here */
+		return;
+    
+	default:
+		US_DEBUGP("-- transport indicates unknown error\n");   
+		srb->result = DID_ERROR << 16;
+		/* Need reset here */
+		return;
+	}
+
+	if ((srb->resid > 0) &&
+	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+	      (srb->cmnd[0] == INQUIRY) ||
+	      (srb->cmnd[0] == MODE_SENSE) ||
+	      (srb->cmnd[0] == LOG_SENSE) ||
+	      (srb->cmnd[0] == MODE_SENSE_10))) {
+		US_DEBUGP("-- unexpectedly short transfer\n");
+		need_auto_sense = 1;
+	}
+
+	if (need_auto_sense) {
+		result = isd200_read_regs(us);
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+			US_DEBUGP("-- auto-sense aborted\n");
+			goto Handle_Abort;
+		}
+		if (result == ISD200_GOOD) {
+			isd200_build_sense(us, srb);
+			srb->result = SAM_STAT_CHECK_CONDITION;
+
+			/* If things are really okay, then let's show that */
+			if ((srb->sense_buffer[2] & 0xf) == 0x0)
+				srb->result = SAM_STAT_GOOD;
+		} else {
+			srb->result = DID_ERROR << 16;
+			/* Need reset here */
+		}
+	}
+
+	/* Regardless of auto-sense, if we _know_ we have an error
+	 * condition, show that in the result code
+	 */
+	if (transferStatus == USB_STOR_TRANSPORT_FAILED)
+		srb->result = SAM_STAT_CHECK_CONDITION;
+	return;
+
+	/* abort processing: the bulk-only transport requires a reset
+	 * following an abort */
+	Handle_Abort:
+	srb->result = DID_ABORT << 16;
+
+	/* permit the reset transfer to take place */
+	clear_bit(US_FLIDX_ABORTING, &us->flags);
+	/* Need reset here */
+}
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+static void isd200_log_config( struct isd200_info* info )
+{
+	US_DEBUGP("      Event Notification: 0x%x\n", 
+		  info->ConfigData.EventNotification);
+	US_DEBUGP("      External Clock: 0x%x\n", 
+		  info->ConfigData.ExternalClock);
+	US_DEBUGP("      ATA Init Timeout: 0x%x\n", 
+		  info->ConfigData.ATAInitTimeout);
+	US_DEBUGP("      ATAPI Command Block Size: 0x%x\n", 
+		  (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6);
+	US_DEBUGP("      Master/Slave Selection: 0x%x\n", 
+		  info->ConfigData.ATAConfig & ATACFG_MASTER);
+	US_DEBUGP("      ATAPI Reset: 0x%x\n",
+		  info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET);
+	US_DEBUGP("      ATA Timing: 0x%x\n",
+		  info->ConfigData.ATAConfig & ATACFG_TIMING);
+	US_DEBUGP("      ATA Major Command: 0x%x\n", 
+		  info->ConfigData.ATAMajorCommand);
+	US_DEBUGP("      ATA Minor Command: 0x%x\n", 
+		  info->ConfigData.ATAMinorCommand);
+	US_DEBUGP("      Init Status: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS);
+	US_DEBUGP("      Config Descriptor 2: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2);
+	US_DEBUGP("      Skip Device Boot: 0x%x\n",
+		  info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT);
+	US_DEBUGP("      ATA 3 State Supsend: 0x%x\n",
+		  info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND);
+	US_DEBUGP("      Descriptor Override: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE);
+	US_DEBUGP("      Last LUN Identifier: 0x%x\n",
+		  info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN);
+	US_DEBUGP("      SRST Enable: 0x%x\n", 
+		  info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST);
+}
+#endif
+
+/**************************************************************************
+ * isd200_write_config
+ *									 
+ * Write the ISD200 Configuration data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_write_config( struct us_data *us ) 
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int result;
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+	US_DEBUGP("Entering isd200_write_config\n");
+	US_DEBUGP("   Writing the following ISD200 Config Data:\n");
+	isd200_log_config(info);
+#endif
+
+	/* let's send the command via the control pipe */
+	result = usb_stor_ctrl_transfer(
+		us, 
+		us->send_ctrl_pipe,
+		0x01, 
+		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+		0x0000, 
+		0x0002, 
+		(void *) &info->ConfigData, 
+		sizeof(info->ConfigData));
+
+	if (result >= 0) {
+		US_DEBUGP("   ISD200 Config Data was written successfully\n");
+	} else {
+		US_DEBUGP("   Request to write ISD200 Config Data failed!\n");
+		retStatus = ISD200_ERROR;
+	}
+
+	US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_read_config
+ *									 
+ * Reads the ISD200 Configuration data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_read_config( struct us_data *us ) 
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int result;
+
+	US_DEBUGP("Entering isd200_read_config\n");
+
+	/* read the configuration information from ISD200.  Use this to */
+	/* determine what the special ATA CDB bytes are.		*/
+
+	result = usb_stor_ctrl_transfer(
+		us, 
+		us->recv_ctrl_pipe,
+		0x02, 
+		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+		0x0000, 
+		0x0002, 
+		(void *) &info->ConfigData, 
+		sizeof(info->ConfigData));
+
+
+	if (result >= 0) {
+		US_DEBUGP("   Retrieved the following ISD200 Config Data:\n");
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		isd200_log_config(info);
+#endif
+	} else {
+		US_DEBUGP("   Request to get ISD200 Config Data failed!\n");
+		retStatus = ISD200_ERROR;
+	}
+
+	US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_atapi_soft_reset
+ *									 
+ * Perform an Atapi Soft Reset on the device
+ *
+ * RETURNS:
+ *    NT status code
+ */
+static int isd200_atapi_soft_reset( struct us_data *us ) 
+{
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering isd200_atapi_soft_reset\n");
+
+	transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 );
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error issuing Atapi Soft Reset\n");
+		retStatus = ISD200_ERROR;
+	}
+
+	US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_srst
+ *									 
+ * Perform an SRST on the device
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_srst( struct us_data *us ) 
+{
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering isd200_SRST\n");
+
+	transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 );
+
+	/* check to see if this request failed */
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error issuing SRST\n");
+		retStatus = ISD200_ERROR;
+	} else {
+		/* delay 10ms to give the drive a chance to see it */
+		msleep(10);
+
+		transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 );
+		if (transferStatus != ISD200_TRANSPORT_GOOD) {
+			US_DEBUGP("   Error taking drive out of reset\n");
+			retStatus = ISD200_ERROR;
+		} else {
+			/* delay 50ms to give the drive a chance to recover after SRST */
+			msleep(50);
+		}
+	}
+
+	US_DEBUGP("Leaving isd200_srst %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_try_enum
+ *									 
+ * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS
+ * and tries to analyze the status registers
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
+			   int detect )
+{
+	int status = ISD200_GOOD;
+	unsigned long endTime;
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	unsigned char *regs = info->RegsBuf;
+	int recheckAsMaster = 0;
+
+	if ( detect )
+		endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ;
+	else
+		endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ;
+
+	/* loop until we detect !BSY or timeout */
+	while(1) {
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+			"Master" : "Slave";
+#endif
+
+		status = isd200_action( us, ACTION_ENUM, NULL, master_slave );
+		if ( status != ISD200_GOOD )
+			break;
+
+		status = isd200_action( us, ACTION_READ_STATUS, 
+					regs, 8 );
+		if ( status != ISD200_GOOD )
+			break;
+
+		if (!detect) {
+			if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) {
+				US_DEBUGP("   %s status is still BSY, try again...\n",mstr);
+			} else {
+				US_DEBUGP("   %s status !BSY, continue with next operation\n",mstr);
+				break;
+			}
+		}
+		/* check for BUSY_STAT and */
+		/* WRERR_STAT (workaround ATA Zip drive) and */ 
+		/* ERR_STAT (workaround for Archos CD-ROM) */
+		else if (regs[IDE_STATUS_OFFSET] & 
+			 (BUSY_STAT | WRERR_STAT | ERR_STAT )) {
+			US_DEBUGP("   Status indicates it is not ready, try again...\n");
+		}
+		/* check for DRDY, ATA devices set DRDY after SRST */
+		else if (regs[IDE_STATUS_OFFSET] & READY_STAT) {
+			US_DEBUGP("   Identified ATA device\n");
+			info->DeviceFlags |= DF_ATA_DEVICE;
+			info->DeviceHead = master_slave;
+			break;
+		} 
+		/* check Cylinder High/Low to
+		   determine if it is an ATAPI device
+		*/
+		else if ((regs[IDE_HCYL_OFFSET] == 0xEB) &&
+			 (regs[IDE_LCYL_OFFSET] == 0x14)) {
+			/* It seems that the RICOH 
+			   MP6200A CD/RW drive will 
+			   report itself okay as a
+			   slave when it is really a
+			   master. So this check again
+			   as a master device just to
+			   make sure it doesn't report
+			   itself okay as a master also
+			*/
+			if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) &&
+			    !recheckAsMaster) {
+				US_DEBUGP("   Identified ATAPI device as slave.  Rechecking again as master\n");
+				recheckAsMaster = 1;
+				master_slave = ATA_ADDRESS_DEVHEAD_STD;
+			} else {
+				US_DEBUGP("   Identified ATAPI device\n");
+				info->DeviceHead = master_slave;
+			      
+				status = isd200_atapi_soft_reset(us);
+				break;
+			}
+		} else {
+ 			US_DEBUGP("   Not ATA, not ATAPI. Weird.\n");
+			break;
+		}
+
+		/* check for timeout on this request */
+		if (time_after_eq(jiffies, endTime)) {
+			if (!detect)
+				US_DEBUGP("   BSY check timeout, just continue with next operation...\n");
+			else
+				US_DEBUGP("   Device detect timeout!\n");
+			break;
+		}
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * isd200_manual_enum
+ *									 
+ * Determines if the drive attached is an ATA or ATAPI and if it is a
+ * master or slave.
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_manual_enum(struct us_data *us)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+
+	US_DEBUGP("Entering isd200_manual_enum\n");
+
+	retStatus = isd200_read_config(us);
+	if (retStatus == ISD200_GOOD) {
+		int isslave;
+		/* master or slave? */
+		retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0);
+		if (retStatus == ISD200_GOOD)
+			retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0);
+
+		if (retStatus == ISD200_GOOD) {
+			retStatus = isd200_srst(us);
+			if (retStatus == ISD200_GOOD)
+				/* ata or atapi? */
+				retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1);
+		}
+
+		isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0;
+		if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) {
+			US_DEBUGP("   Setting Master/Slave selection to %d\n", isslave);
+			info->ConfigData.ATAConfig &= 0x3f;
+			info->ConfigData.ATAConfig |= (isslave<<6);
+			retStatus = isd200_write_config(us);
+		}
+	}
+
+	US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus);
+	return(retStatus);
+}
+
+
+/**************************************************************************
+ * isd200_get_inquiry_data
+ *
+ * Get inquiry data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_get_inquiry_data( struct us_data *us )
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	struct hd_driveid *id = info->id;
+
+	US_DEBUGP("Entering isd200_get_inquiry_data\n");
+
+	/* set default to Master */
+	info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD;
+
+	/* attempt to manually enumerate this device */
+	retStatus = isd200_manual_enum(us);
+	if (retStatus == ISD200_GOOD) {
+		int transferStatus;
+
+		/* check for an ATA device */
+		if (info->DeviceFlags & DF_ATA_DEVICE) {
+			/* this must be an ATA device */
+			/* perform an ATA Command Identify */
+			transferStatus = isd200_action( us, ACTION_IDENTIFY,
+							id, 
+							sizeof(struct hd_driveid) );
+			if (transferStatus != ISD200_TRANSPORT_GOOD) {
+				/* Error issuing ATA Command Identify */
+				US_DEBUGP("   Error issuing ATA Command Identify\n");
+				retStatus = ISD200_ERROR;
+			} else {
+				/* ATA Command Identify successful */
+				int i;
+				__be16 *src;
+				__u16 *dest;
+				ide_fix_driveid(id);
+
+				US_DEBUGP("   Identify Data Structure:\n");
+				US_DEBUGP("      config = 0x%x\n", id->config);
+				US_DEBUGP("      cyls = 0x%x\n", id->cyls);
+				US_DEBUGP("      heads = 0x%x\n", id->heads);
+				US_DEBUGP("      track_bytes = 0x%x\n", id->track_bytes);
+				US_DEBUGP("      sector_bytes = 0x%x\n", id->sector_bytes);
+				US_DEBUGP("      sectors = 0x%x\n", id->sectors);
+				US_DEBUGP("      serial_no[0] = 0x%x\n", id->serial_no[0]);
+				US_DEBUGP("      buf_type = 0x%x\n", id->buf_type);
+				US_DEBUGP("      buf_size = 0x%x\n", id->buf_size);
+				US_DEBUGP("      ecc_bytes = 0x%x\n", id->ecc_bytes);
+				US_DEBUGP("      fw_rev[0] = 0x%x\n", id->fw_rev[0]);
+				US_DEBUGP("      model[0] = 0x%x\n", id->model[0]);
+				US_DEBUGP("      max_multsect = 0x%x\n", id->max_multsect);
+				US_DEBUGP("      dword_io = 0x%x\n", id->dword_io);
+				US_DEBUGP("      capability = 0x%x\n", id->capability);
+				US_DEBUGP("      tPIO = 0x%x\n", id->tPIO);
+				US_DEBUGP("      tDMA = 0x%x\n", id->tDMA);
+				US_DEBUGP("      field_valid = 0x%x\n", id->field_valid);
+				US_DEBUGP("      cur_cyls = 0x%x\n", id->cur_cyls);
+				US_DEBUGP("      cur_heads = 0x%x\n", id->cur_heads);
+				US_DEBUGP("      cur_sectors = 0x%x\n", id->cur_sectors);
+				US_DEBUGP("      cur_capacity = 0x%x\n", (id->cur_capacity1 << 16) + id->cur_capacity0 );
+				US_DEBUGP("      multsect = 0x%x\n", id->multsect);
+				US_DEBUGP("      lba_capacity = 0x%x\n", id->lba_capacity);
+				US_DEBUGP("      command_set_1 = 0x%x\n", id->command_set_1);
+				US_DEBUGP("      command_set_2 = 0x%x\n", id->command_set_2);
+
+				memset(&info->InquiryData, 0, sizeof(info->InquiryData));
+
+				/* Standard IDE interface only supports disks */
+				info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE;
+
+				/* The length must be at least 36 (5 + 31) */
+				info->InquiryData.AdditionalLength = 0x1F;
+
+				if (id->command_set_1 & COMMANDSET_MEDIA_STATUS) {
+					/* set the removable bit */
+					info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE;
+					info->DeviceFlags |= DF_REMOVABLE_MEDIA;
+				}
+
+				/* Fill in vendor identification fields */
+				src = (__be16*)id->model;
+				dest = (__u16*)info->InquiryData.VendorId;
+				for (i=0;i<4;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__be16*)(id->model+8);
+				dest = (__u16*)info->InquiryData.ProductId;
+				for (i=0;i<8;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__be16*)id->fw_rev;
+				dest = (__u16*)info->InquiryData.ProductRevisionLevel;
+				for (i=0;i<2;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				/* determine if it supports Media Status Notification */
+				if (id->command_set_2 & COMMANDSET_MEDIA_STATUS) {
+					US_DEBUGP("   Device supports Media Status Notification\n");
+
+					/* Indicate that it is enabled, even though it is not
+					 * This allows the lock/unlock of the media to work
+					 * correctly.
+					 */
+					info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED;
+				}
+				else
+					info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED;
+
+			}
+		} else {
+			/* 
+			 * this must be an ATAPI device 
+			 * use an ATAPI protocol (Transparent SCSI)
+			 */
+			us->protocol_name = "Transparent SCSI";
+			us->proto_handler = usb_stor_transparent_scsi_command;
+
+			US_DEBUGP("Protocol changed to: %s\n", us->protocol_name);
+	    
+			/* Free driver structure */	    
+			us->extra_destructor(info);
+			us->extra = NULL;
+			us->extra_destructor = NULL;
+		}
+	}
+
+	US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus);
+
+	return(retStatus);
+}
+
+
+/**************************************************************************
+ * isd200_scsi_to_ata
+ *									 
+ * Translate SCSI commands to ATA commands.
+ *
+ * RETURNS:
+ *    1 if the command needs to be sent to the transport layer
+ *    0 otherwise
+ */
+static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us,
+			      union ata_cdb * ataCdb)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	struct hd_driveid *id = info->id;
+	int sendToTransport = 1;
+	unsigned char sectnum, head;
+	unsigned short cylinder;
+	unsigned long lba;
+	unsigned long blockCount;
+	unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	memset(ataCdb, 0, sizeof(union ata_cdb));
+
+	/* SCSI Command */
+	switch (srb->cmnd[0]) {
+	case INQUIRY:
+		US_DEBUGP("   ATA OUT - INQUIRY\n");
+
+		/* copy InquiryData */
+		usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData,
+				sizeof(info->InquiryData), srb);
+		srb->result = SAM_STAT_GOOD;
+		sendToTransport = 0;
+		break;
+
+	case MODE_SENSE:
+		US_DEBUGP("   ATA OUT - SCSIOP_MODE_SENSE\n");
+
+		/* Initialize the return buffer */
+		usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb);
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Media Status not supported, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	case TEST_UNIT_READY:
+		US_DEBUGP("   ATA OUT - SCSIOP_TEST_UNIT_READY\n");
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Media Status not supported, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	case READ_CAPACITY:
+	{
+		unsigned long capacity;
+		struct read_capacity_data readCapacityData;
+
+		US_DEBUGP("   ATA OUT - SCSIOP_READ_CAPACITY\n");
+
+		if (id->capability & CAPABILITY_LBA ) {
+			capacity = id->lba_capacity - 1;
+		} else {
+			capacity = (id->heads *
+				    id->cyls *
+				    id->sectors) - 1;
+		}
+		readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
+		readCapacityData.BytesPerBlock = cpu_to_be32(0x200);
+
+		usb_stor_set_xfer_buf((unsigned char *) &readCapacityData,
+				sizeof(readCapacityData), srb);
+		srb->result = SAM_STAT_GOOD;
+		sendToTransport = 0;
+	}
+	break;
+
+	case READ_10:
+		US_DEBUGP("   ATA OUT - SCSIOP_READ\n");
+
+		lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (id->capability & CAPABILITY_LBA) {
+			sectnum = (unsigned char)(lba);
+			cylinder = (unsigned short)(lba>>8);
+			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
+		} else {
+			sectnum = (unsigned char)((lba % id->sectors) + 1);
+			cylinder = (unsigned short)(lba / (id->sectors *
+							   id->heads));
+			head = (unsigned char)((lba / id->sectors) %
+					       id->heads);
+		}
+		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+		ataCdb->generic.TransferBlockSize = 1;
+		ataCdb->generic.RegisterSelect =
+		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_DEVICE_HEAD  | REG_COMMAND;
+		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
+		ataCdb->write.SectorNumberByte = sectnum;
+		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
+		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
+		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
+		ataCdb->write.CommandByte = WIN_READ;
+		break;
+
+	case WRITE_10:
+		US_DEBUGP("   ATA OUT - SCSIOP_WRITE\n");
+
+		lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (id->capability & CAPABILITY_LBA) {
+			sectnum = (unsigned char)(lba);
+			cylinder = (unsigned short)(lba>>8);
+			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
+		} else {
+			sectnum = (unsigned char)((lba % id->sectors) + 1);
+			cylinder = (unsigned short)(lba / (id->sectors * id->heads));
+			head = (unsigned char)((lba / id->sectors) % id->heads);
+		}
+		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+		ataCdb->generic.TransferBlockSize = 1;
+		ataCdb->generic.RegisterSelect =
+		  REG_SECTOR_COUNT | REG_SECTOR_NUMBER |
+		  REG_CYLINDER_LOW | REG_CYLINDER_HIGH |
+		  REG_DEVICE_HEAD  | REG_COMMAND;
+		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
+		ataCdb->write.SectorNumberByte = sectnum;
+		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
+		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
+		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
+		ataCdb->write.CommandByte = WIN_WRITE;
+		break;
+
+	case ALLOW_MEDIUM_REMOVAL:
+		US_DEBUGP("   ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
+
+		if (info->DeviceFlags & DF_REMOVABLE_MEDIA) {
+			US_DEBUGP("   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+	    
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
+				WIN_DOORLOCK : WIN_DOORUNLOCK;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Not removeable media, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	case START_STOP:    
+		US_DEBUGP("   ATA OUT - SCSIOP_START_STOP_UNIT\n");
+		US_DEBUGP("   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+
+		if ((srb->cmnd[4] & 0x3) == 0x2) {
+			US_DEBUGP("   Media Eject\n");
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 0;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
+		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
+			US_DEBUGP("   Get Media Status\n");
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->generic.RegisterSelect = REG_COMMAND;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Nothing to do, just report okay\n");
+			srb->result = SAM_STAT_GOOD;
+			sendToTransport = 0;
+		}
+		break;
+
+	default:
+		US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]);
+		srb->result = DID_ERROR << 16;
+		sendToTransport = 0;
+		break;
+	}
+
+	return(sendToTransport);
+}
+
+
+/**************************************************************************
+ * isd200_free_info
+ *
+ * Frees the driver structure.
+ */
+static void isd200_free_info_ptrs(void *info_)
+{
+	struct isd200_info *info = (struct isd200_info *) info_;
+
+	if (info) {
+		kfree(info->id);
+		kfree(info->RegsBuf);
+	}
+}
+
+/**************************************************************************
+ * isd200_init_info
+ *									 
+ * Allocates (if necessary) and initializes the driver structure.
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_init_info(struct us_data *us)
+{
+	int retStatus = ISD200_GOOD;
+	struct isd200_info *info;
+
+	info = (struct isd200_info *)
+			kmalloc(sizeof(struct isd200_info), GFP_KERNEL);
+	if (!info)
+		retStatus = ISD200_ERROR;
+	else {
+		memset(info, 0, sizeof(struct isd200_info));
+		info->id = (struct hd_driveid *)
+				kmalloc(sizeof(struct hd_driveid), GFP_KERNEL);
+		info->RegsBuf = (unsigned char *)
+				kmalloc(sizeof(info->ATARegs), GFP_KERNEL);
+		if (!info->id || !info->RegsBuf) {
+			isd200_free_info_ptrs(info);
+			kfree(info);
+			retStatus = ISD200_ERROR;
+		} else
+			memset(info->id, 0, sizeof(struct hd_driveid));
+	}
+
+	if (retStatus == ISD200_GOOD) {
+		us->extra = info;
+		us->extra_destructor = isd200_free_info_ptrs;
+	} else
+		US_DEBUGP("ERROR - kmalloc failure\n");
+
+	return(retStatus);
+}
+
+/**************************************************************************
+ * Initialization for the ISD200 
+ */
+
+int isd200_Initialization(struct us_data *us)
+{
+	US_DEBUGP("ISD200 Initialization...\n");
+
+	/* Initialize ISD200 info struct */
+
+	if (isd200_init_info(us) == ISD200_ERROR) {
+		US_DEBUGP("ERROR Initializing ISD200 Info struct\n");
+	} else {
+		/* Get device specific data */
+
+		if (isd200_get_inquiry_data(us) != ISD200_GOOD)
+			US_DEBUGP("ISD200 Initialization Failure\n");
+		else
+			US_DEBUGP("ISD200 Initialization complete\n");
+	}
+
+	return 0;
+}
+
+
+/**************************************************************************
+ * Protocol and Transport for the ISD200 ASIC
+ *
+ * This protocol and transport are for ATA devices connected to an ISD200
+ * ASIC.  An ATAPI device that is conected as a slave device will be
+ * detected in the driver initialization function and the protocol will
+ * be changed to an ATAPI protocol (Transparent SCSI).
+ *
+ */
+
+void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int sendToTransport = 1;
+	union ata_cdb ataCdb;
+
+	/* Make sure driver was initialized */
+
+	if (us->extra == NULL)
+		US_DEBUGP("ERROR Driver not initialized\n");
+
+	/* Convert command */
+	srb->resid = 0;
+	sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
+
+	/* send the command to the transport layer */
+	if (sendToTransport)
+		isd200_invoke_transport(us, srb, &ataCdb);
+}
diff --git a/drivers/usb/storage/isd200.h b/drivers/usb/storage/isd200.h
new file mode 100644
index 0000000..0a35f4f
--- /dev/null
+++ b/drivers/usb/storage/isd200.h
@@ -0,0 +1,31 @@
+/* Header File for In-System Design, Inc. ISD200 ASIC
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 In-System Design, Inc. (support@in-system.com)
+ *
+ * See isd200.c for more information.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_ISD200_H
+#define _USB_ISD200_H
+
+extern void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us);
+extern int isd200_Initialization(struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
new file mode 100644
index 0000000..aff9d51
--- /dev/null
+++ b/drivers/usb/storage/jumpshot.c
@@ -0,0 +1,596 @@
+/* Driver for Lexar "Jumpshot" Compact Flash reader
+ *
+ * $Id: jumpshot.c,v 1.7 2002/02/25 00:40:13 mdharm Exp $
+ *
+ * jumpshot driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
+ *
+ *   Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *   which I used as a template for this driver.
+ *
+ *   Some bugfixes and scatter-gather code by Gregory P. Smith 
+ *   (greg-usb@electricrain.com)
+ *
+ *   Fix for media change by Joerg Schneider (js@joergschneider.com)
+ *
+ * Developed with the assistance of:
+ *
+ *   (C) 2002 Alan Stern <stern@rowland.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+ 
+ /*
+  * This driver attempts to support the Lexar Jumpshot USB CompactFlash 
+  * reader.  Like many other USB CompactFlash readers, the Jumpshot contains
+  * a USB-to-ATA chip. 
+  *
+  * This driver supports reading and writing.  If you're truly paranoid,
+  * however, you can force the driver into a write-protected state by setting
+  * the WP enable bits in jumpshot_handle_mode_sense.  See the comments
+  * in that routine.
+  */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "jumpshot.h"
+
+
+static inline int jumpshot_bulk_read(struct us_data *us,
+				     unsigned char *data, 
+				     unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("jumpshot_bulk_read:  len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static inline int jumpshot_bulk_write(struct us_data *us,
+				      unsigned char *data, 
+				      unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("jumpshot_bulk_write:  len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			data, len, NULL);
+}
+
+
+static int jumpshot_get_status(struct us_data  *us)
+{
+	int rc;
+
+	if (!us)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// send the setup
+	rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
+				   0, 0xA0, 0, 7, us->iobuf, 1);
+
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (us->iobuf[0] != 0x50) {
+		US_DEBUGP("jumpshot_get_status:  0x%2x\n",
+			  us->iobuf[0]);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int jumpshot_read_data(struct us_data *us,
+			      struct jumpshot_info *info,
+			      u32 sector,
+			      u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't read more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >>  8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 | ((sector >> 24) & 0x0F);
+		command[6] = 0x20;
+
+		// send the setup + command
+		result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+					       0, 0x20, 0, 1, command, 7);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result
+		result = jumpshot_bulk_read(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		US_DEBUGP("jumpshot_read_data:  %d bytes\n", len);
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				 &sg_idx, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+
+static int jumpshot_write_data(struct us_data *us,
+			       struct jumpshot_info *info,
+			       u32 sector,
+			       u32 sectors)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result, waitcount;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't write more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&sg_idx, &sg_offset, FROM_XFER_BUF);
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >>  8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] = 0xE0 | ((sector >> 24) & 0x0F);
+		command[6] = 0x30;
+
+		// send the setup + command
+		result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+			0, 0x20, 0, 1, command, 7);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// send the data
+		result = jumpshot_bulk_write(us, buffer, len);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
+
+		// read the result.  apparently the bulk write can complete
+		// before the jumpshot drive is finished writing.  so we loop
+		// here until we get a good return code
+		waitcount = 0;
+		do {
+			result = jumpshot_get_status(us);
+			if (result != USB_STOR_TRANSPORT_GOOD) {
+				// I have not experimented to find the smallest value.
+				//
+				msleep(50); 
+			}
+		} while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10));
+
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			US_DEBUGP("jumpshot_write_data:  Gah!  Waitcount = 10.  Bad write!?\n");
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return result;
+
+ leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+static int jumpshot_id_device(struct us_data *us,
+			      struct jumpshot_info *info)
+{
+	unsigned char *command = us->iobuf;
+	unsigned char *reply;
+	int 	 rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	command[0] = 0xE0;
+	command[1] = 0xEC;
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// send the setup
+	rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+				   0, 0x20, 0, 6, command, 2);
+
+	if (rc != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("jumpshot_id_device:  Gah! "
+			  "send_control for read_capacity failed\n");
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	// read the reply
+	rc = jumpshot_bulk_read(us, reply, 512);
+	if (rc != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	info->sectors = ((u32)(reply[117]) << 24) |
+			((u32)(reply[116]) << 16) |
+			((u32)(reply[115]) <<  8) |
+			((u32)(reply[114])      );
+
+	rc = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+static int jumpshot_handle_mode_sense(struct us_data *us,
+				      struct scsi_cmnd * srb, 
+				      int sense_6)
+{
+	static unsigned char rw_err_page[12] = {
+		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
+	};
+	static unsigned char cache_page[12] = {
+		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char rbac_page[12] = {
+		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	static unsigned char timer_page[8] = {
+		0x1C, 0x6, 0, 0, 0, 0
+	};
+	unsigned char pc, page_code;
+	unsigned int i = 0;
+	struct jumpshot_info *info = (struct jumpshot_info *) (us->extra);
+	unsigned char *ptr = us->iobuf;
+
+	pc = srb->cmnd[2] >> 6;
+	page_code = srb->cmnd[2] & 0x3F;
+
+	switch (pc) {
+	   case 0x0:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Current values\n");
+		break;
+	   case 0x1:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Changeable values\n");
+		break;
+	   case 0x2:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Default values\n");
+		break;
+	   case 0x3:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Saves values\n");
+		break;
+	}
+
+	memset(ptr, 0, 8);
+	if (sense_6) {
+		ptr[2] = 0x00;		// WP enable: 0x80
+		i = 4;
+	} else {
+		ptr[3] = 0x00;		// WP enable: 0x80
+		i = 8;
+	}
+
+	switch (page_code) {
+	   case 0x0:
+		// vendor-specific mode
+		info->sense_key = 0x05;
+		info->sense_asc = 0x24;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+
+	   case 0x1:
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+
+	   case 0x8:
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		break;
+
+	   case 0x1B:
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		break;
+
+	   case 0x1C:
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		break;
+
+	   case 0x3F:
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		i += sizeof(rw_err_page);
+		break;
+	}
+
+	if (sense_6)
+		ptr[0] = i - 1;
+	else
+		((__be16 *) ptr)[0] = cpu_to_be16(i - 2);
+	usb_stor_set_xfer_buf(ptr, i, srb);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static void jumpshot_info_destructor(void *extra)
+{
+	// this routine is a placeholder...
+	// currently, we don't allocate any extra blocks so we're okay
+}
+
+
+
+// Transport for the Lexar 'Jumpshot'
+//
+int jumpshot_transport(struct scsi_cmnd * srb, struct us_data *us)
+{
+	struct jumpshot_info *info;
+	int rc;
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[8] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (!us->extra) {
+		us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
+		if (!us->extra) {
+			US_DEBUGP("jumpshot_transport:  Gah! Can't allocate storage for jumpshot info struct!\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+		memset(us->extra, 0, sizeof(struct jumpshot_info));
+		us->extra_destructor = jumpshot_info_destructor;
+	}
+
+	info = (struct jumpshot_info *) (us->extra);
+
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("jumpshot_transport:  INQUIRY.  Returning bogus response.\n");
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+
+		rc = jumpshot_get_status(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		rc = jumpshot_id_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		US_DEBUGP("jumpshot_transport:  READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
+			  info->sectors, info->ssize);
+
+		// build the reply
+		//
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		US_DEBUGP("jumpshot_transport:  Gah! MODE_SELECT_10.\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("jumpshot_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// I don't think we'll ever see a READ_12 but support it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("jumpshot_transport:  READ_12: read block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("jumpshot_transport:  WRITE_10: write block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// I don't think we'll ever see a WRITE_12 but support it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+			((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+			 ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("jumpshot_transport:  WRITE_12: write block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_write_data(us, info, block, blocks);
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		US_DEBUGP("jumpshot_transport:  TEST_UNIT_READY.\n");
+		return jumpshot_get_status(us);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("jumpshot_transport:  REQUEST_SENSE.\n");
+
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+		US_DEBUGP("jumpshot_transport:  MODE_SENSE_6 detected\n");
+		return jumpshot_handle_mode_sense(us, srb, 1);
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		US_DEBUGP("jumpshot_transport:  MODE_SENSE_10 detected\n");
+		return jumpshot_handle_mode_sense(us, srb, 0);
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		// sure.  whatever.  not like we can stop the user from popping
+		// the media out of the device (no locking doors, etc)
+		//
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		/* this is used by sd.c'check_scsidisk_media_change to detect
+		   media change */
+		US_DEBUGP("jumpshot_transport:  START_STOP.\n");
+		/* the first jumpshot_id_device after a media change returns
+		   an error (determined experimentally) */
+		rc = jumpshot_id_device(us, info);
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->sense_key = NO_SENSE;
+			srb->result = SUCCESS;
+		} else {
+			info->sense_key = UNIT_ATTENTION;
+			srb->result = SAM_STAT_CHECK_CONDITION;
+		}
+		return rc;
+	}
+
+	US_DEBUGP("jumpshot_transport:  Gah! Unknown command: %d (0x%x)\n",
+		  srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
diff --git a/drivers/usb/storage/jumpshot.h b/drivers/usb/storage/jumpshot.h
new file mode 100644
index 0000000..19bac9d
--- /dev/null
+++ b/drivers/usb/storage/jumpshot.h
@@ -0,0 +1,39 @@
+/* Driver for Lexar "Jumpshot" USB Compact Flash reader
+ * Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
+ *
+ * See jumpshot.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_JUMPSHOT_H
+#define _USB_JUMPSHOT_H
+
+extern int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+struct jumpshot_info {
+   unsigned long   sectors;     // total sector count
+   unsigned long   ssize;       // sector size in bytes
+ 
+   // the following aren't used yet
+   unsigned char   sense_key;
+   unsigned long   sense_asc;   // additional sense code
+   unsigned long   sense_ascq;  // additional sense code qualifier
+};
+
+#endif
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
new file mode 100644
index 0000000..9ad3042
--- /dev/null
+++ b/drivers/usb/storage/protocol.c
@@ -0,0 +1,254 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * $Id: protocol.c,v 1.14 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2002 Alan Stern (stern@rowland.org)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/highmem.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "protocol.h"
+#include "debug.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+/***********************************************************************
+ * Protocol routines
+ ***********************************************************************/
+
+void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	/* Pad the ATAPI command with zeros 
+	 *
+	 * NOTE: This only works because a scsi_cmnd struct field contains
+	 * a unsigned char cmnd[16], so we know we have storage available
+	 */
+	for (; srb->cmd_len<12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	/* set command length to 12 bytes */
+	srb->cmd_len = 12;
+
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+
+void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	/* Pad the ATAPI command with zeros 
+	 *
+	 * NOTE: This only works because a scsi_cmnd struct field contains
+	 * a unsigned char cmnd[16], so we know we have storage available
+	 */
+
+	/* Pad the ATAPI command with zeros */
+	for (; srb->cmd_len<12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	/* set command length to 12 bytes */
+	srb->cmd_len = 12;
+
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+
+
+void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
+{
+	/* fix some commands -- this is a form of mode translation
+	 * UFI devices only accept 12 byte long commands 
+	 *
+	 * NOTE: This only works because a scsi_cmnd struct field contains
+	 * a unsigned char cmnd[16], so we know we have storage available
+	 */
+
+	/* Pad the ATAPI command with zeros */
+	for (; srb->cmd_len<12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	/* set command length to 12 bytes (this affects the transport layer) */
+	srb->cmd_len = 12;
+
+	/* XXX We should be constantly re-evaluating the need for these */
+
+	/* determine the correct data length for these commands */
+	switch (srb->cmnd[0]) {
+
+		/* for INQUIRY, UFI devices only ever return 36 bytes */
+	case INQUIRY:
+		srb->cmnd[4] = 36;
+		break;
+
+		/* again, for MODE_SENSE_10, we get the minimum (8) */
+	case MODE_SENSE_10:
+		srb->cmnd[7] = 0;
+		srb->cmnd[8] = 8;
+		break;
+
+		/* for REQUEST_SENSE, UFI devices only ever return 18 bytes */
+	case REQUEST_SENSE:
+		srb->cmnd[4] = 18;
+		break;
+	} /* end switch on cmnd[0] */
+
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+
+void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
+				       struct us_data *us)
+{
+	/* send the command to the transport layer */
+	usb_stor_invoke_transport(srb, us);
+}
+
+/***********************************************************************
+ * Scatter-gather transfer buffer access routines
+ ***********************************************************************/
+
+/* Copy a buffer of length buflen to/from the srb's transfer buffer.
+ * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer
+ * points to a list of s-g entries and we ignore srb->request_bufflen.
+ * For non-scatter-gather transfers, srb->request_buffer points to the
+ * transfer buffer itself and srb->request_bufflen is the buffer's length.)
+ * Update the *index and *offset variables so that the next copy will
+ * pick up from where this one left off. */
+
+unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
+	unsigned int *offset, enum xfer_buf_dir dir)
+{
+	unsigned int cnt;
+
+	/* If not using scatter-gather, just transfer the data directly.
+	 * Make certain it will fit in the available buffer space. */
+	if (srb->use_sg == 0) {
+		if (*offset >= srb->request_bufflen)
+			return 0;
+		cnt = min(buflen, srb->request_bufflen - *offset);
+		if (dir == TO_XFER_BUF)
+			memcpy((unsigned char *) srb->request_buffer + *offset,
+					buffer, cnt);
+		else
+			memcpy(buffer, (unsigned char *) srb->request_buffer +
+					*offset, cnt);
+		*offset += cnt;
+
+	/* Using scatter-gather.  We have to go through the list one entry
+	 * at a time.  Each s-g entry contains some number of pages, and
+	 * each page has to be kmap()'ed separately.  If the page is already
+	 * in kernel-addressable memory then kmap() will return its address.
+	 * If the page is not directly accessible -- such as a user buffer
+	 * located in high memory -- then kmap() will map it to a temporary
+	 * position in the kernel's virtual address space. */
+	} else {
+		struct scatterlist *sg =
+				(struct scatterlist *) srb->request_buffer
+				+ *index;
+
+		/* This loop handles a single s-g list entry, which may
+		 * include multiple pages.  Find the initial page structure
+		 * and the starting offset within the page, and update
+		 * the *offset and *index values for the next loop. */
+		cnt = 0;
+		while (cnt < buflen && *index < srb->use_sg) {
+			struct page *page = sg->page +
+					((sg->offset + *offset) >> PAGE_SHIFT);
+			unsigned int poff =
+					(sg->offset + *offset) & (PAGE_SIZE-1);
+			unsigned int sglen = sg->length - *offset;
+
+			if (sglen > buflen - cnt) {
+
+				/* Transfer ends within this s-g entry */
+				sglen = buflen - cnt;
+				*offset += sglen;
+			} else {
+
+				/* Transfer continues to next s-g entry */
+				*offset = 0;
+				++*index;
+				++sg;
+			}
+
+			/* Transfer the data for all the pages in this
+			 * s-g entry.  For each page: call kmap(), do the
+			 * transfer, and call kunmap() immediately after. */
+			while (sglen > 0) {
+				unsigned int plen = min(sglen, (unsigned int)
+						PAGE_SIZE - poff);
+				unsigned char *ptr = kmap(page);
+
+				if (dir == TO_XFER_BUF)
+					memcpy(ptr + poff, buffer + cnt, plen);
+				else
+					memcpy(buffer + cnt, ptr + poff, plen);
+				kunmap(page);
+
+				/* Start at the beginning of the next page */
+				poff = 0;
+				++page;
+				cnt += plen;
+				sglen -= plen;
+			}
+		}
+	}
+
+	/* Return the amount actually transferred */
+	return cnt;
+}
+
+/* Store the contents of buffer into srb's transfer buffer and set the
+ * SCSI residue. */
+void usb_stor_set_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb)
+{
+	unsigned int index = 0, offset = 0;
+
+	usb_stor_access_xfer_buf(buffer, buflen, srb, &index, &offset,
+			TO_XFER_BUF);
+	if (buflen < srb->request_bufflen)
+		srb->resid = srb->request_bufflen - buflen;
+}
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
new file mode 100644
index 0000000..02bff01
--- /dev/null
+++ b/drivers/usb/storage/protocol.h
@@ -0,0 +1,74 @@
+/* Driver for USB Mass Storage compliant devices
+ * Protocol Functions Header File
+ *
+ * $Id: protocol.h,v 1.4 2001/02/13 07:10:03 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _PROTOCOL_H_
+#define _PROTOCOL_H_
+
+/* Sub Classes */
+
+#define US_SC_RBC	0x01		/* Typically, flash devices */
+#define US_SC_8020	0x02		/* CD-ROM */
+#define US_SC_QIC	0x03		/* QIC-157 Tapes */
+#define US_SC_UFI	0x04		/* Floppy */
+#define US_SC_8070	0x05		/* Removable media */
+#define US_SC_SCSI	0x06		/* Transparent */
+#define US_SC_ISD200    0x07		/* ISD200 ATA */
+#define US_SC_MIN	US_SC_RBC
+#define US_SC_MAX	US_SC_ISD200
+
+#define US_SC_DEVICE	0xff		/* Use device's value */
+
+/* Protocol handling routines */
+extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
+		struct us_data*);
+
+/* struct scsi_cmnd transfer buffer access utilities */
+enum xfer_buf_dir	{TO_XFER_BUF, FROM_XFER_BUF};
+
+extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb, unsigned int *index,
+	unsigned int *offset, enum xfer_buf_dir dir);
+
+extern void usb_stor_set_xfer_buf(unsigned char *buffer,
+	unsigned int buflen, struct scsi_cmnd *srb);
+#endif
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
new file mode 100644
index 0000000..22e48a2
--- /dev/null
+++ b/drivers/usb/storage/scsiglue.c
@@ -0,0 +1,500 @@
+/* Driver for USB Mass Storage compliant devices
+ * SCSI layer glue code
+ *
+ * $Id: scsiglue.c,v 1.26 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_devinfo.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "debug.h"
+#include "transport.h"
+#include "protocol.h"
+
+/***********************************************************************
+ * Host functions 
+ ***********************************************************************/
+
+static const char* host_info(struct Scsi_Host *host)
+{
+	return "SCSI emulation for USB Mass Storage devices";
+}
+
+static int slave_alloc (struct scsi_device *sdev)
+{
+	/*
+	 * Set the INQUIRY transfer length to 36.  We don't use any of
+	 * the extra data and many devices choke if asked for more or
+	 * less than 36 bytes.
+	 */
+	sdev->inquiry_len = 36;
+	return 0;
+}
+
+static int slave_configure(struct scsi_device *sdev)
+{
+	struct us_data *us = host_to_us(sdev->host);
+
+	/* Scatter-gather buffers (all but the last) must have a length
+	 * divisible by the bulk maxpacket size.  Otherwise a data packet
+	 * would end up being short, causing a premature end to the data
+	 * transfer.  Since high-speed bulk pipes have a maxpacket size
+	 * of 512, we'll use that as the scsi device queue's DMA alignment
+	 * mask.  Guaranteeing proper alignment of the first buffer will
+	 * have the desired effect because, except at the beginning and
+	 * the end, scatter-gather buffers follow page boundaries. */
+	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
+
+	/* Set the SCSI level to at least 2.  We'll leave it at 3 if that's
+	 * what is originally reported.  We need this to avoid confusing
+	 * the SCSI layer with devices that report 0 or 1, but need 10-byte
+	 * commands (ala ATAPI devices behind certain bridges, or devices
+	 * which simply have broken INQUIRY data).
+	 *
+	 * NOTE: This means /dev/sg programs (ala cdrecord) will get the
+	 * actual information.  This seems to be the preference for
+	 * programs like that.
+	 *
+	 * NOTE: This also means that /proc/scsi/scsi and sysfs may report
+	 * the actual value or the modified one, depending on where the
+	 * data comes from.
+	 */
+	if (sdev->scsi_level < SCSI_2)
+		sdev->scsi_level = SCSI_2;
+
+	/* According to the technical support people at Genesys Logic,
+	 * devices using their chips have problems transferring more than
+	 * 32 KB at a time.  In practice people have found that 64 KB
+	 * works okay and that's what Windows does.  But we'll be
+	 * conservative; people can always use the sysfs interface to
+	 * increase max_sectors. */
+	if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS &&
+			sdev->request_queue->max_sectors > 64)
+		blk_queue_max_sectors(sdev->request_queue, 64);
+
+	/* We can't put these settings in slave_alloc() because that gets
+	 * called before the device type is known.  Consequently these
+	 * settings can't be overridden via the scsi devinfo mechanism. */
+	if (sdev->type == TYPE_DISK) {
+
+		/* Disk-type devices use MODE SENSE(6) if the protocol
+		 * (SubClass) is Transparent SCSI, otherwise they use
+		 * MODE SENSE(10). */
+		if (us->subclass != US_SC_SCSI)
+			sdev->use_10_for_ms = 1;
+
+		/* Many disks only accept MODE SENSE transfer lengths of
+		 * 192 bytes (that's what Windows uses). */
+		sdev->use_192_bytes_for_3f = 1;
+
+		/* Some devices don't like MODE SENSE with page=0x3f,
+		 * which is the command used for checking if a device
+		 * is write-protected.  Now that we tell the sd driver
+		 * to do a 192-byte transfer with this command the
+		 * majority of devices work fine, but a few still can't
+		 * handle it.  The sd driver will simply assume those
+		 * devices are write-enabled. */
+		if (us->flags & US_FL_NO_WP_DETECT)
+			sdev->skip_ms_page_3f = 1;
+
+		/* A number of devices have problems with MODE SENSE for
+		 * page x08, so we will skip it. */
+		sdev->skip_ms_page_8 = 1;
+
+		/* Some disks return the total number of blocks in response
+		 * to READ CAPACITY rather than the highest block number.
+		 * If this device makes that mistake, tell the sd driver. */
+		if (us->flags & US_FL_FIX_CAPACITY)
+			sdev->fix_capacity = 1;
+	} else {
+
+		/* Non-disk-type devices don't need to blacklist any pages
+		 * or to force 192-byte transfer lengths for MODE SENSE.
+		 * But they do need to use MODE SENSE(10). */
+		sdev->use_10_for_ms = 1;
+	}
+
+	/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
+	 * REMOVAL command, so suppress those commands. */
+	if (us->flags & US_FL_NOT_LOCKABLE)
+		sdev->lockable = 0;
+
+	/* this is to satisfy the compiler, tho I don't think the 
+	 * return code is ever checked anywhere. */
+	return 0;
+}
+
+/* queue a command */
+/* This is always called with scsi_lock(host) held */
+static int queuecommand(struct scsi_cmnd *srb,
+			void (*done)(struct scsi_cmnd *))
+{
+	struct us_data *us = host_to_us(srb->device->host);
+
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	/* check for state-transition errors */
+	if (us->srb != NULL) {
+		printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
+			__FUNCTION__, us->srb);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	/* fail the command if we are disconnecting */
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		US_DEBUGP("Fail command during disconnect\n");
+		srb->result = DID_NO_CONNECT << 16;
+		done(srb);
+		return 0;
+	}
+
+	/* enqueue the command and wake up the control thread */
+	srb->scsi_done = done;
+	us->srb = srb;
+	up(&(us->sema));
+
+	return 0;
+}
+
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command timeout and abort */
+/* This is always called with scsi_lock(host) held */
+static int command_abort(struct scsi_cmnd *srb)
+{
+	struct us_data *us = host_to_us(srb->device->host);
+
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	/* Is this command still active? */
+	if (us->srb != srb) {
+		US_DEBUGP ("-- nothing to abort\n");
+		return FAILED;
+	}
+
+	/* Set the TIMED_OUT bit.  Also set the ABORTING bit, but only if
+	 * a device reset isn't already in progress (to avoid interfering
+	 * with the reset).  To prevent races with auto-reset, we must
+	 * stop any ongoing USB transfers while still holding the host
+	 * lock. */
+	set_bit(US_FLIDX_TIMED_OUT, &us->flags);
+	if (!test_bit(US_FLIDX_RESETTING, &us->flags)) {
+		set_bit(US_FLIDX_ABORTING, &us->flags);
+		usb_stor_stop_transport(us);
+	}
+	scsi_unlock(us_to_host(us));
+
+	/* Wait for the aborted command to finish */
+	wait_for_completion(&us->notify);
+
+	/* Reacquire the lock and allow USB transfers to resume */
+	scsi_lock(us_to_host(us));
+	clear_bit(US_FLIDX_ABORTING, &us->flags);
+	clear_bit(US_FLIDX_TIMED_OUT, &us->flags);
+	return SUCCESS;
+}
+
+/* This invokes the transport reset mechanism to reset the state of the
+ * device */
+/* This is always called with scsi_lock(host) held */
+static int device_reset(struct scsi_cmnd *srb)
+{
+	struct us_data *us = host_to_us(srb->device->host);
+	int result;
+
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	scsi_unlock(us_to_host(us));
+
+	/* lock the device pointers and do the reset */
+	down(&(us->dev_semaphore));
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		result = FAILED;
+		US_DEBUGP("No reset during disconnect\n");
+	} else
+		result = us->transport_reset(us);
+	up(&(us->dev_semaphore));
+
+	/* lock the host for the return */
+	scsi_lock(us_to_host(us));
+	return result;
+}
+
+/* This resets the device's USB port. */
+/* It refuses to work if there's more than one interface in
+ * the device, so that other users are not affected. */
+/* This is always called with scsi_lock(host) held */
+static int bus_reset(struct scsi_cmnd *srb)
+{
+	struct us_data *us = host_to_us(srb->device->host);
+	int result, rc;
+
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	scsi_unlock(us_to_host(us));
+
+	/* The USB subsystem doesn't handle synchronisation between
+	 * a device's several drivers. Therefore we reset only devices
+	 * with just one interface, which we of course own. */
+
+	down(&(us->dev_semaphore));
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		result = -EIO;
+		US_DEBUGP("No reset during disconnect\n");
+	} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
+		result = -EBUSY;
+		US_DEBUGP("Refusing to reset a multi-interface device\n");
+	} else {
+		rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+		if (rc < 0) {
+			US_DEBUGP("unable to lock device for reset: %d\n", rc);
+			result = rc;
+		} else {
+			result = usb_reset_device(us->pusb_dev);
+			if (rc)
+				usb_unlock_device(us->pusb_dev);
+			US_DEBUGP("usb_reset_device returns %d\n", result);
+		}
+	}
+	up(&(us->dev_semaphore));
+
+	/* lock the host for the return */
+	scsi_lock(us_to_host(us));
+	return result < 0 ? FAILED : SUCCESS;
+}
+
+/* Report a driver-initiated device reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must own the SCSI host lock. */
+void usb_stor_report_device_reset(struct us_data *us)
+{
+	int i;
+	struct Scsi_Host *host = us_to_host(us);
+
+	scsi_report_device_reset(host, 0, 0);
+	if (us->flags & US_FL_SCM_MULT_TARG) {
+		for (i = 1; i < host->max_id; ++i)
+			scsi_report_device_reset(host, 0, i);
+	}
+}
+
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+/* we use this macro to help us write into the buffer */
+#undef SPRINTF
+#define SPRINTF(args...) \
+	do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
+
+static int proc_info (struct Scsi_Host *host, char *buffer,
+		char **start, off_t offset, int length, int inout)
+{
+	struct us_data *us = host_to_us(host);
+	char *pos = buffer;
+	const char *string;
+
+	/* if someone is sending us data, just throw it away */
+	if (inout)
+		return length;
+
+	/* print the controller name */
+	SPRINTF("   Host scsi%d: usb-storage\n", host->host_no);
+
+	/* print product, vendor, and serial number strings */
+	if (us->pusb_dev->manufacturer)
+		string = us->pusb_dev->manufacturer;
+	else if (us->unusual_dev->vendorName)
+		string = us->unusual_dev->vendorName;
+	else
+		string = "Unknown";
+	SPRINTF("       Vendor: %s\n", string);
+	if (us->pusb_dev->product)
+		string = us->pusb_dev->product;
+	else if (us->unusual_dev->productName)
+		string = us->unusual_dev->productName;
+	else
+		string = "Unknown";
+	SPRINTF("      Product: %s\n", string);
+	if (us->pusb_dev->serial)
+		string = us->pusb_dev->serial;
+	else
+		string = "None";
+	SPRINTF("Serial Number: %s\n", string);
+
+	/* show the protocol and transport */
+	SPRINTF("     Protocol: %s\n", us->protocol_name);
+	SPRINTF("    Transport: %s\n", us->transport_name);
+
+	/* show the device flags */
+	if (pos < buffer + length) {
+		pos += sprintf(pos, "       Quirks:");
+
+#define US_FLAG(name, value) \
+	if (us->flags & value) pos += sprintf(pos, " " #name);
+US_DO_ALL_FLAGS
+#undef US_FLAG
+
+		*(pos++) = '\n';
+	}
+
+	/*
+	 * Calculate start of next buffer, and return value.
+	 */
+	*start = buffer + offset;
+
+	if ((pos - buffer) < offset)
+		return (0);
+	else if ((pos - buffer - offset) < length)
+		return (pos - buffer - offset);
+	else
+		return (length);
+}
+
+/***********************************************************************
+ * Sysfs interface
+ ***********************************************************************/
+
+/* Output routine for the sysfs max_sectors file */
+static ssize_t show_max_sectors(struct device *dev, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+
+	return sprintf(buf, "%u\n", sdev->request_queue->max_sectors);
+}
+
+/* Input routine for the sysfs max_sectors file */
+static ssize_t store_max_sectors(struct device *dev, const char *buf,
+		size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	unsigned short ms;
+
+	if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
+		blk_queue_max_sectors(sdev->request_queue, ms);
+		return strlen(buf);
+	}
+	return -EINVAL;	
+}
+
+static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors,
+		store_max_sectors);
+
+static struct device_attribute *sysfs_device_attr_list[] = {
+		&dev_attr_max_sectors,
+		NULL,
+		};
+
+/*
+ * this defines our host template, with which we'll allocate hosts
+ */
+
+struct scsi_host_template usb_stor_host_template = {
+	/* basic userland interface stuff */
+	.name =				"usb-storage",
+	.proc_name =			"usb-storage",
+	.proc_info =			proc_info,
+	.info =				host_info,
+
+	/* command interface -- queued only */
+	.queuecommand =			queuecommand,
+
+	/* error and abort handlers */
+	.eh_abort_handler =		command_abort,
+	.eh_device_reset_handler =	device_reset,
+	.eh_bus_reset_handler =		bus_reset,
+
+	/* queue commands only, only one command per LUN */
+	.can_queue =			1,
+	.cmd_per_lun =			1,
+
+	/* unknown initiator id */
+	.this_id =			-1,
+
+	.slave_alloc =			slave_alloc,
+	.slave_configure =		slave_configure,
+
+	/* lots of sg segments can be handled */
+	.sg_tablesize =			SG_ALL,
+
+	/* limit the total size of a transfer to 120 KB */
+	.max_sectors =                  240,
+
+	/* merge commands... this seems to help performance, but
+	 * periodically someone should test to see which setting is more
+	 * optimal.
+	 */
+	.use_clustering =		1,
+
+	/* emulated HBA */
+	.emulated =			1,
+
+	/* we do our own delay after a device or bus reset */
+	.skip_settle_delay =		1,
+
+	/* sysfs device attributes */
+	.sdev_attrs =			sysfs_device_attr_list,
+
+	/* module management */
+	.module =			THIS_MODULE
+};
+
+/* To Report "Illegal Request: Invalid Field in CDB */
+unsigned char usb_stor_sense_invalidCDB[18] = {
+	[0]	= 0x70,			    /* current error */
+	[2]	= ILLEGAL_REQUEST,	    /* Illegal Request = 0x05 */
+	[7]	= 0x0a,			    /* additional length */
+	[12]	= 0x24			    /* Invalid Field in CDB */
+};
+
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
new file mode 100644
index 0000000..d0a49af
--- /dev/null
+++ b/drivers/usb/storage/scsiglue.h
@@ -0,0 +1,49 @@
+/* Driver for USB Mass Storage compliant devices
+ * SCSI Connecting Glue Header File
+ *
+ * $Id: scsiglue.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SCSIGLUE_H_
+#define _SCSIGLUE_H_
+
+extern void usb_stor_report_device_reset(struct us_data *us);
+
+extern unsigned char usb_stor_sense_invalidCDB[18];
+extern struct scsi_host_template usb_stor_host_template;
+
+#endif
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
new file mode 100644
index 0000000..0ea2f5a
--- /dev/null
+++ b/drivers/usb/storage/sddr09.c
@@ -0,0 +1,1608 @@
+/* Driver for SanDisk SDDR-09 SmartMedia reader
+ *
+ * $Id: sddr09.c,v 1.24 2002/04/22 03:39:43 mdharm Exp $
+ *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ *   (c) 2002 Andries Brouwer (aeb@cwi.nl)
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
+ * This chip is a programmable USB controller. In the SDDR-09, it has
+ * been programmed to obey a certain limited set of SCSI commands.
+ * This driver translates the "real" SCSI commands to the SDDR-09 SCSI
+ * commands.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Known vendor commands: 12 bytes, first byte is opcode
+ *
+ * E7: read scatter gather
+ * E8: read
+ * E9: write
+ * EA: erase
+ * EB: reset
+ * EC: read status
+ * ED: read ID
+ * EE: write CIS (?)
+ * EF: compute checksum (?)
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "sddr09.h"
+
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+/* #define US_DEBUGP printk */
+
+/*
+ * First some stuff that does not belong here:
+ * data on SmartMedia and other cards, completely
+ * unrelated to this driver.
+ * Similar stuff occurs in <linux/mtd/nand_ids.h>.
+ */
+
+struct nand_flash_dev {
+	int model_id;
+	int chipshift;		/* 1<<cs bytes total capacity */
+	char pageshift;		/* 1<<ps bytes in a page */
+	char blockshift;	/* 1<<bs pages in an erase block */
+	char zoneshift;		/* 1<<zs blocks in a zone */
+				/* # of logical blocks is 125/128 of this */
+	char pageadrlen;	/* length of an address in bytes - 1 */
+};
+
+/*
+ * NAND Flash Manufacturer ID Codes
+ */
+#define NAND_MFR_AMD		0x01
+#define NAND_MFR_NATSEMI	0x8f
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+
+static inline char *nand_flash_manufacturer(int manuf_id) {
+	switch(manuf_id) {
+	case NAND_MFR_AMD:
+		return "AMD";
+	case NAND_MFR_NATSEMI:
+		return "NATSEMI";
+	case NAND_MFR_TOSHIBA:
+		return "Toshiba";
+	case NAND_MFR_SAMSUNG:
+		return "Samsung";
+	default:
+		return "unknown";
+	}
+}
+
+/*
+ * It looks like it is unnecessary to attach manufacturer to the
+ * remaining data: SSFDC prescribes manufacturer-independent id codes.
+ *
+ * 256 MB NAND flash has a 5-byte ID with 2nd byte 0xaa, 0xba, 0xca or 0xda.
+ */
+
+static struct nand_flash_dev nand_flash_ids[] = {
+	/* NAND flash */
+	{ 0x6e, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0xe8, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0xec, 20, 8, 4, 8, 2},	/* 1 MB */
+	{ 0x64, 21, 8, 4, 9, 2}, 	/* 2 MB */
+	{ 0xea, 21, 8, 4, 9, 2},	/* 2 MB */
+	{ 0x6b, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe3, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe5, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xe6, 23, 9, 4, 10, 2},	/* 8 MB */
+	{ 0x73, 24, 9, 5, 10, 2},	/* 16 MB */
+	{ 0x75, 25, 9, 5, 10, 2},	/* 32 MB */
+	{ 0x76, 26, 9, 5, 10, 3},	/* 64 MB */
+	{ 0x79, 27, 9, 5, 10, 3},	/* 128 MB */
+
+	/* MASK ROM */
+	{ 0x5d, 21, 9, 4, 8, 2},	/* 2 MB */
+	{ 0xd5, 22, 9, 4, 9, 2},	/* 4 MB */
+	{ 0xd6, 23, 9, 4, 10, 2},	/* 8 MB */
+	{ 0x57, 24, 9, 4, 11, 2},	/* 16 MB */
+	{ 0x58, 25, 9, 4, 12, 2},	/* 32 MB */
+	{ 0,}
+};
+
+#define SIZE(a)	(sizeof(a)/sizeof((a)[0]))
+
+static struct nand_flash_dev *
+nand_find_id(unsigned char id) {
+	int i;
+
+	for (i = 0; i < SIZE(nand_flash_ids); i++)
+		if (nand_flash_ids[i].model_id == id)
+			return &(nand_flash_ids[i]);
+	return NULL;
+}
+
+/*
+ * ECC computation.
+ */
+static unsigned char parity[256];
+static unsigned char ecc2[256];
+
+static void nand_init_ecc(void) {
+	int i, j, a;
+
+	parity[0] = 0;
+	for (i = 1; i < 256; i++)
+		parity[i] = (parity[i&(i-1)] ^ 1);
+
+	for (i = 0; i < 256; i++) {
+		a = 0;
+		for (j = 0; j < 8; j++) {
+			if (i & (1<<j)) {
+				if ((j & 1) == 0)
+					a ^= 0x04;
+				if ((j & 2) == 0)
+					a ^= 0x10;
+				if ((j & 4) == 0)
+					a ^= 0x40;
+			}
+		}
+		ecc2[i] = ~(a ^ (a<<1) ^ (parity[i] ? 0xa8 : 0));
+	}
+}
+
+/* compute 3-byte ecc on 256 bytes */
+static void nand_compute_ecc(unsigned char *data, unsigned char *ecc) {
+	int i, j, a;
+	unsigned char par, bit, bits[8];
+
+	par = 0;
+	for (j = 0; j < 8; j++)
+		bits[j] = 0;
+
+	/* collect 16 checksum bits */
+	for (i = 0; i < 256; i++) {
+		par ^= data[i];
+		bit = parity[data[i]];
+		for (j = 0; j < 8; j++)
+			if ((i & (1<<j)) == 0)
+				bits[j] ^= bit;
+	}
+
+	/* put 4+4+4 = 12 bits in the ecc */
+	a = (bits[3] << 6) + (bits[2] << 4) + (bits[1] << 2) + bits[0];
+	ecc[0] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	a = (bits[7] << 6) + (bits[6] << 4) + (bits[5] << 2) + bits[4];
+	ecc[1] = ~(a ^ (a<<1) ^ (parity[par] ? 0xaa : 0));
+
+	ecc[2] = ecc2[par];
+}
+
+static int nand_compare_ecc(unsigned char *data, unsigned char *ecc) {
+	return (data[0] == ecc[0] && data[1] == ecc[1] && data[2] == ecc[2]);
+}
+
+static void nand_store_ecc(unsigned char *data, unsigned char *ecc) {
+	memcpy(data, ecc, 3);
+}
+
+/*
+ * The actual driver starts here.
+ */
+
+/*
+ * On my 16MB card, control blocks have size 64 (16 real control bytes,
+ * and 48 junk bytes). In reality of course the card uses 16 control bytes,
+ * so the reader makes up the remaining 48. Don't know whether these numbers
+ * depend on the card. For now a constant.
+ */
+#define CONTROL_SHIFT 6
+
+/*
+ * On my Combo CF/SM reader, the SM reader has LUN 1.
+ * (and things fail with LUN 0).
+ * It seems LUN is irrelevant for others.
+ */
+#define LUN	1
+#define	LUNBITS	(LUN << 5)
+
+/*
+ * LBA and PBA are unsigned ints. Special values.
+ */
+#define UNDEF    0xffffffff
+#define SPARE    0xfffffffe
+#define UNUSABLE 0xfffffffd
+
+static int erase_bad_lba_entries = 0;
+
+/* send vendor interface command (0x41) */
+/* called for requests 0, 1, 8 */
+static int
+sddr09_send_command(struct us_data *us,
+		    unsigned char request,
+		    unsigned char direction,
+		    unsigned char *xfer_data,
+		    unsigned int xfer_len) {
+	unsigned int pipe;
+	unsigned char requesttype = (0x41 | direction);
+	int rc;
+
+	// Get the receive or send control pipe number
+
+	if (direction == USB_DIR_IN)
+		pipe = us->recv_ctrl_pipe;
+	else
+		pipe = us->send_ctrl_pipe;
+
+	rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype,
+				   0, 0, xfer_data, xfer_len);
+	return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD :
+			USB_STOR_TRANSPORT_ERROR);
+}
+
+static int
+sddr09_send_scsi_command(struct us_data *us,
+			 unsigned char *command,
+			 unsigned int command_len) {
+	return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len);
+}
+
+#if 0
+/*
+ * Test Unit Ready Command: 12 bytes.
+ * byte 0: opcode: 00
+ */
+static int
+sddr09_test_unit_ready(struct us_data *us) {
+	unsigned char *command = us->iobuf;
+	int result;
+
+	memset(command, 0, 6);
+	command[1] = LUNBITS;
+
+	result = sddr09_send_scsi_command(us, command, 6);
+
+	US_DEBUGP("sddr09_test_unit_ready returns %d\n", result);
+
+	return result;
+}
+#endif
+
+/*
+ * Request Sense Command: 12 bytes.
+ * byte 0: opcode: 03
+ * byte 4: data length
+ */
+static int
+sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) {
+	unsigned char *command = us->iobuf;
+	int result;
+
+	memset(command, 0, 12);
+	command[0] = 0x03;
+	command[1] = LUNBITS;
+	command[4] = buflen;
+
+	result = sddr09_send_scsi_command(us, command, 12);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("request sense failed\n");
+		return result;
+	}
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			sensebuf, buflen, NULL);
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("request sense bulk in failed\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	} else {
+		US_DEBUGP("request sense worked\n");
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+}
+
+/*
+ * Read Command: 12 bytes.
+ * byte 0: opcode: E8
+ * byte 1: last two bits: 00: read data, 01: read blockwise control,
+ *			10: read both, 11: read pagewise control.
+ *	 It turns out we need values 20, 21, 22, 23 here (LUN 1).
+ * bytes 2-5: address (interpretation depends on byte 1, see below)
+ * bytes 10-11: count (idem)
+ *
+ * A page has 512 data bytes and 64 control bytes (16 control and 48 junk).
+ * A read data command gets data in 512-byte pages.
+ * A read control command gets control in 64-byte chunks.
+ * A read both command gets data+control in 576-byte chunks.
+ *
+ * Blocks are groups of 32 pages, and read blockwise control jumps to the
+ * next block, while read pagewise control jumps to the next page after
+ * reading a group of 64 control bytes.
+ * [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?]
+ *
+ * (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.)
+ */
+
+static int
+sddr09_readX(struct us_data *us, int x, unsigned long fromaddress,
+	     int nr_of_pages, int bulklen, unsigned char *buf,
+	     int use_sg) {
+
+	unsigned char *command = us->iobuf;
+	int result;
+
+	command[0] = 0xE8;
+	command[1] = LUNBITS | x;
+	command[2] = MSB_of(fromaddress>>16);
+	command[3] = LSB_of(fromaddress>>16); 
+	command[4] = MSB_of(fromaddress & 0xFFFF);
+	command[5] = LSB_of(fromaddress & 0xFFFF); 
+	command[6] = 0;
+	command[7] = 0;
+	command[8] = 0;
+	command[9] = 0;
+	command[10] = MSB_of(nr_of_pages);
+	command[11] = LSB_of(nr_of_pages);
+
+	result = sddr09_send_scsi_command(us, command, 12);
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result for send_control in sddr09_read2%d %d\n",
+			  x, result);
+		return result;
+	}
+
+	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
+				       buf, bulklen, use_sg, NULL);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n",
+			  x, result);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read Data
+ *
+ * fromaddress counts data shorts:
+ * increasing it by 256 shifts the bytestream by 512 bytes;
+ * the last 8 bits are ignored.
+ *
+ * nr_of_pages counts pages of size (1 << pageshift).
+ */
+static int
+sddr09_read20(struct us_data *us, unsigned long fromaddress,
+	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
+	int bulklen = nr_of_pages << pageshift;
+
+	/* The last 8 bits of fromaddress are ignored. */
+	return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen,
+			    buf, use_sg);
+}
+
+/*
+ * Read Blockwise Control
+ *
+ * fromaddress gives the starting position (as in read data;
+ * the last 8 bits are ignored); increasing it by 32*256 shifts
+ * the output stream by 64 bytes.
+ *
+ * count counts control groups of size (1 << controlshift).
+ * For me, controlshift = 6. Is this constant?
+ *
+ * After getting one control group, jump to the next block
+ * (fromaddress += 8192).
+ */
+static int
+sddr09_read21(struct us_data *us, unsigned long fromaddress,
+	      int count, int controlshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (count << controlshift);
+	return sddr09_readX(us, 1, fromaddress, count, bulklen,
+			    buf, use_sg);
+}
+
+/*
+ * Read both Data and Control
+ *
+ * fromaddress counts data shorts, ignoring control:
+ * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes;
+ * the last 8 bits are ignored.
+ *
+ * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift).
+ */
+static int
+sddr09_read22(struct us_data *us, unsigned long fromaddress,
+	      int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
+	US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n",
+		  nr_of_pages, bulklen);
+	return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen,
+			    buf, use_sg);
+}
+
+#if 0
+/*
+ * Read Pagewise Control
+ *
+ * fromaddress gives the starting position (as in read data;
+ * the last 8 bits are ignored); increasing it by 256 shifts
+ * the output stream by 64 bytes.
+ *
+ * count counts control groups of size (1 << controlshift).
+ * For me, controlshift = 6. Is this constant?
+ *
+ * After getting one control group, jump to the next page
+ * (fromaddress += 256).
+ */
+static int
+sddr09_read23(struct us_data *us, unsigned long fromaddress,
+	      int count, int controlshift, unsigned char *buf, int use_sg) {
+
+	int bulklen = (count << controlshift);
+	return sddr09_readX(us, 3, fromaddress, count, bulklen,
+			    buf, use_sg);
+}
+#endif
+
+/*
+ * Erase Command: 12 bytes.
+ * byte 0: opcode: EA
+ * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
+ * 
+ * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
+ * The byte address being erased is 2*Eaddress.
+ * The CIS cannot be erased.
+ */
+static int
+sddr09_erase(struct us_data *us, unsigned long Eaddress) {
+	unsigned char *command = us->iobuf;
+	int result;
+
+	US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress);
+
+	memset(command, 0, 12);
+	command[0] = 0xEA;
+	command[1] = LUNBITS;
+	command[6] = MSB_of(Eaddress>>16);
+	command[7] = LSB_of(Eaddress>>16);
+	command[8] = MSB_of(Eaddress & 0xFFFF);
+	command[9] = LSB_of(Eaddress & 0xFFFF);
+
+	result = sddr09_send_scsi_command(us, command, 12);
+
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		US_DEBUGP("Result for send_control in sddr09_erase %d\n",
+			  result);
+
+	return result;
+}
+
+/*
+ * Write CIS Command: 12 bytes.
+ * byte 0: opcode: EE
+ * bytes 2-5: write address in shorts
+ * bytes 10-11: sector count
+ *
+ * This writes at the indicated address. Don't know how it differs
+ * from E9. Maybe it does not erase? However, it will also write to
+ * the CIS.
+ *
+ * When two such commands on the same page follow each other directly,
+ * the second one is not done.
+ */
+
+/*
+ * Write Command: 12 bytes.
+ * byte 0: opcode: E9
+ * bytes 2-5: write address (big-endian, counting shorts, sector aligned).
+ * bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
+ * bytes 10-11: sector count (big-endian, in 512-byte sectors).
+ *
+ * If write address equals erase address, the erase is done first,
+ * otherwise the write is done first. When erase address equals zero
+ * no erase is done?
+ */
+static int
+sddr09_writeX(struct us_data *us,
+	      unsigned long Waddress, unsigned long Eaddress,
+	      int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) {
+
+	unsigned char *command = us->iobuf;
+	int result;
+
+	command[0] = 0xE9;
+	command[1] = LUNBITS;
+
+	command[2] = MSB_of(Waddress>>16);
+	command[3] = LSB_of(Waddress>>16);
+	command[4] = MSB_of(Waddress & 0xFFFF);
+	command[5] = LSB_of(Waddress & 0xFFFF);
+
+	command[6] = MSB_of(Eaddress>>16);
+	command[7] = LSB_of(Eaddress>>16);
+	command[8] = MSB_of(Eaddress & 0xFFFF);
+	command[9] = LSB_of(Eaddress & 0xFFFF);
+
+	command[10] = MSB_of(nr_of_pages);
+	command[11] = LSB_of(nr_of_pages);
+
+	result = sddr09_send_scsi_command(us, command, 12);
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result for send_control in sddr09_writeX %d\n",
+			  result);
+		return result;
+	}
+
+	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
+				       buf, bulklen, use_sg, NULL);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
+			  result);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* erase address, write same address */
+static int
+sddr09_write_inplace(struct us_data *us, unsigned long address,
+		     int nr_of_pages, int pageshift, unsigned char *buf,
+		     int use_sg) {
+	int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT);
+	return sddr09_writeX(us, address, address, nr_of_pages, bulklen,
+			     buf, use_sg);
+}
+
+#if 0
+/*
+ * Read Scatter Gather Command: 3+4n bytes.
+ * byte 0: opcode E7
+ * byte 2: n
+ * bytes 4i-1,4i,4i+1: page address
+ * byte 4i+2: page count
+ * (i=1..n)
+ *
+ * This reads several pages from the card to a single memory buffer.
+ * The last two bits of byte 1 have the same meaning as for E8.
+ */
+static int
+sddr09_read_sg_test_only(struct us_data *us) {
+	unsigned char *command = us->iobuf;
+	int result, bulklen, nsg, ct;
+	unsigned char *buf;
+	unsigned long address;
+
+	nsg = bulklen = 0;
+	command[0] = 0xE7;
+	command[1] = LUNBITS;
+	command[2] = 0;
+	address = 040000; ct = 1;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	address = 0340000; ct = 1;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	address = 01000000; ct = 2;
+	nsg++;
+	bulklen += (ct << 9);
+	command[4*nsg+2] = ct;
+	command[4*nsg+1] = ((address >> 9) & 0xFF);
+	command[4*nsg+0] = ((address >> 17) & 0xFF);
+	command[4*nsg-1] = ((address >> 25) & 0xFF);
+
+	command[2] = nsg;
+
+	result = sddr09_send_scsi_command(us, command, 4*nsg+3);
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
+			  result);
+		return result;
+	}
+
+	buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO);
+	if (!buf)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				       buf, bulklen, NULL);
+	kfree(buf);
+	if (result != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
+			  result);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+#endif
+
+/*
+ * Read Status Command: 12 bytes.
+ * byte 0: opcode: EC
+ *
+ * Returns 64 bytes, all zero except for the first.
+ * bit 0: 1: Error
+ * bit 5: 1: Suspended
+ * bit 6: 1: Ready
+ * bit 7: 1: Not write-protected
+ */
+
+static int
+sddr09_read_status(struct us_data *us, unsigned char *status) {
+
+	unsigned char *command = us->iobuf;
+	unsigned char *data = us->iobuf;
+	int result;
+
+	US_DEBUGP("Reading status...\n");
+
+	memset(command, 0, 12);
+	command[0] = 0xEC;
+	command[1] = LUNBITS;
+
+	result = sddr09_send_scsi_command(us, command, 12);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				       data, 64, NULL);
+	*status = data[0];
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+}
+
+static int
+sddr09_read_data(struct us_data *us,
+		 unsigned long address,
+		 unsigned int sectors) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned char *buffer;
+	unsigned int lba, maxlba, pba;
+	unsigned int page, pages;
+	unsigned int len, index, offset;
+	int result;
+
+	// Since we only read in one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL) {
+		printk("sddr09_read_data: Out of memory\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	// Figure out the initial LBA and page
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+	maxlba = info->capacity >> (info->pageshift + info->blockshift);
+
+	// This could be made much more efficient by checking for
+	// contiguous LBA's. Another exercise left to the student.
+
+	result = USB_STOR_TRANSPORT_GOOD;
+	index = offset = 0;
+
+	while (sectors > 0) {
+
+		/* Find number of pages we can read in this block */
+		pages = min(sectors, info->blocksize - page);
+		len = pages << info->pageshift;
+
+		/* Not overflowing capacity? */
+		if (lba >= maxlba) {
+			US_DEBUGP("Error: Requested lba %u exceeds "
+				  "maximum %u\n", lba, maxlba);
+			result = USB_STOR_TRANSPORT_ERROR;
+			break;
+		}
+
+		/* Find where this lba lives on disk */
+		pba = info->lba_to_pba[lba];
+
+		if (pba == UNDEF) {	/* this lba was never written */
+
+			US_DEBUGP("Read %d zero pages (LBA %d) page %d\n",
+				  pages, lba, page);
+
+			/* This is not really an error. It just means
+			   that the block has never been written.
+			   Instead of returning USB_STOR_TRANSPORT_ERROR
+			   it is better to return all zero data. */
+
+			memset(buffer, 0, len);
+
+		} else {
+			US_DEBUGP("Read %d pages, from PBA %d"
+				  " (LBA %d) page %d\n",
+				  pages, pba, lba, page);
+
+			address = ((pba << info->blockshift) + page) << 
+				info->pageshift;
+
+			result = sddr09_read20(us, address>>1,
+					pages, info->pageshift, buffer, 0);
+			if (result != USB_STOR_TRANSPORT_GOOD)
+				break;
+		}
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&index, &offset, TO_XFER_BUF);
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+	}
+
+	kfree(buffer);
+	return result;
+}
+
+static unsigned int
+sddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) {
+	static unsigned int lastpba = 1;
+	int zonestart, end, i;
+
+	zonestart = (lba/1000) << 10;
+	end = info->capacity >> (info->blockshift + info->pageshift);
+	end -= zonestart;
+	if (end > 1024)
+		end = 1024;
+
+	for (i = lastpba+1; i < end; i++) {
+		if (info->pba_to_lba[zonestart+i] == UNDEF) {
+			lastpba = i;
+			return zonestart+i;
+		}
+	}
+	for (i = 0; i <= lastpba; i++) {
+		if (info->pba_to_lba[zonestart+i] == UNDEF) {
+			lastpba = i;
+			return zonestart+i;
+		}
+	}
+	return 0;
+}
+
+static int
+sddr09_write_lba(struct us_data *us, unsigned int lba,
+		 unsigned int page, unsigned int pages,
+		 unsigned char *ptr, unsigned char *blockbuffer) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned long address;
+	unsigned int pba, lbap;
+	unsigned int pagelen;
+	unsigned char *bptr, *cptr, *xptr;
+	unsigned char ecc[3];
+	int i, result, isnew;
+
+	lbap = ((lba % 1000) << 1) | 0x1000;
+	if (parity[MSB_of(lbap) ^ LSB_of(lbap)])
+		lbap ^= 1;
+	pba = info->lba_to_pba[lba];
+	isnew = 0;
+
+	if (pba == UNDEF) {
+		pba = sddr09_find_unused_pba(info, lba);
+		if (!pba) {
+			printk("sddr09_write_lba: Out of unused blocks\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+		info->pba_to_lba[pba] = lba;
+		info->lba_to_pba[lba] = pba;
+		isnew = 1;
+	}
+
+	if (pba == 1) {
+		/* Maybe it is impossible to write to PBA 1.
+		   Fake success, but don't do anything. */
+		printk("sddr09: avoid writing to pba 1\n");
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+
+	/* read old contents */
+	address = (pba << (info->pageshift + info->blockshift));
+	result = sddr09_read22(us, address>>1, info->blocksize,
+			       info->pageshift, blockbuffer, 0);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	/* check old contents and fill lba */
+	for (i = 0; i < info->blocksize; i++) {
+		bptr = blockbuffer + i*pagelen;
+		cptr = bptr + info->pagesize;
+		nand_compute_ecc(bptr, ecc);
+		if (!nand_compare_ecc(cptr+13, ecc)) {
+			US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n",
+				  i, pba);
+			nand_store_ecc(cptr+13, ecc);
+		}
+		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
+		if (!nand_compare_ecc(cptr+8, ecc)) {
+			US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n",
+				  i, pba);
+			nand_store_ecc(cptr+8, ecc);
+		}
+		cptr[6] = cptr[11] = MSB_of(lbap);
+		cptr[7] = cptr[12] = LSB_of(lbap);
+	}
+
+	/* copy in new stuff and compute ECC */
+	xptr = ptr;
+	for (i = page; i < page+pages; i++) {
+		bptr = blockbuffer + i*pagelen;
+		cptr = bptr + info->pagesize;
+		memcpy(bptr, xptr, info->pagesize);
+		xptr += info->pagesize;
+		nand_compute_ecc(bptr, ecc);
+		nand_store_ecc(cptr+13, ecc);
+		nand_compute_ecc(bptr+(info->pagesize / 2), ecc);
+		nand_store_ecc(cptr+8, ecc);
+	}
+
+	US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba);
+
+	result = sddr09_write_inplace(us, address>>1, info->blocksize,
+				      info->pageshift, blockbuffer, 0);
+
+	US_DEBUGP("sddr09_write_inplace returns %d\n", result);
+
+#if 0
+	{
+		unsigned char status = 0;
+		int result2 = sddr09_read_status(us, &status);
+		if (result2 != USB_STOR_TRANSPORT_GOOD)
+			US_DEBUGP("sddr09_write_inplace: cannot read status\n");
+		else if (status != 0xc0)
+			US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
+				  status);
+	}
+#endif
+
+#if 0
+	{
+		int result2 = sddr09_test_unit_ready(us);
+	}
+#endif
+
+	return result;
+}
+
+static int
+sddr09_write_data(struct us_data *us,
+		  unsigned long address,
+		  unsigned int sectors) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	unsigned int lba, page, pages;
+	unsigned int pagelen, blocklen;
+	unsigned char *blockbuffer;
+	unsigned char *buffer;
+	unsigned int len, index, offset;
+	int result;
+
+	// blockbuffer is used for reading in the old data, overwriting
+	// with the new data, and performing ECC calculations
+
+	/* TODO: instead of doing kmalloc/kfree for each write,
+	   add a bufferpointer to the info structure */
+
+	pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT);
+	blocklen = (pagelen << info->blockshift);
+	blockbuffer = kmalloc(blocklen, GFP_NOIO);
+	if (!blockbuffer) {
+		printk("sddr09_write_data: Out of memory\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	// Since we don't write the user data directly to the device,
+	// we have to create a bounce buffer and move the data a piece
+	// at a time between the bounce buffer and the actual transfer buffer.
+
+	len = min(sectors, (unsigned int) info->blocksize) * info->pagesize;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL) {
+		printk("sddr09_write_data: Out of memory\n");
+		kfree(blockbuffer);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	// Figure out the initial LBA and page
+	lba = address >> info->blockshift;
+	page = (address & info->blockmask);
+
+	result = USB_STOR_TRANSPORT_GOOD;
+	index = offset = 0;
+
+	while (sectors > 0) {
+
+		// Write as many sectors as possible in this block
+
+		pages = min(sectors, info->blocksize - page);
+		len = (pages << info->pageshift);
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&index, &offset, FROM_XFER_BUF);
+
+		result = sddr09_write_lba(us, lba, page, pages,
+				buffer, blockbuffer);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			break;
+
+		page = 0;
+		lba++;
+		sectors -= pages;
+	}
+
+	kfree(buffer);
+	kfree(blockbuffer);
+
+	return result;
+}
+
+static int
+sddr09_read_control(struct us_data *us,
+		unsigned long address,
+		unsigned int blocks,
+		unsigned char *content,
+		int use_sg) {
+
+	US_DEBUGP("Read control address %lu, blocks %d\n",
+		address, blocks);
+
+	return sddr09_read21(us, address, blocks,
+			     CONTROL_SHIFT, content, use_sg);
+}
+
+/*
+ * Read Device ID Command: 12 bytes.
+ * byte 0: opcode: ED
+ *
+ * Returns 2 bytes: Manufacturer ID and Device ID.
+ * On more recent cards 3 bytes: the third byte is an option code A5
+ * signifying that the secret command to read an 128-bit ID is available.
+ * On still more recent cards 4 bytes: the fourth byte C0 means that
+ * a second read ID cmd is available.
+ */
+static int
+sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) {
+	unsigned char *command = us->iobuf;
+	unsigned char *content = us->iobuf;
+	int result, i;
+
+	memset(command, 0, 12);
+	command[0] = 0xED;
+	command[1] = LUNBITS;
+
+	result = sddr09_send_scsi_command(us, command, 12);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			content, 64, NULL);
+
+	for (i = 0; i < 4; i++)
+		deviceID[i] = content[i];
+
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+}
+
+static int
+sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) {
+	int result;
+	unsigned char status;
+
+	result = sddr09_read_status(us, &status);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_get_wp: read_status fails\n");
+		return result;
+	}
+	US_DEBUGP("sddr09_get_wp: status 0x%02X", status);
+	if ((status & 0x80) == 0) {
+		info->flags |= SDDR09_WP;	/* write protected */
+		US_DEBUGP(" WP");
+	}
+	if (status & 0x40)
+		US_DEBUGP(" Ready");
+	if (status & LUNBITS)
+		US_DEBUGP(" Suspended");
+	if (status & 0x1)
+		US_DEBUGP(" Error");
+	US_DEBUGP("\n");
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+#if 0
+/*
+ * Reset Command: 12 bytes.
+ * byte 0: opcode: EB
+ */
+static int
+sddr09_reset(struct us_data *us) {
+
+	unsigned char *command = us->iobuf;
+
+	memset(command, 0, 12);
+	command[0] = 0xEB;
+	command[1] = LUNBITS;
+
+	return sddr09_send_scsi_command(us, command, 12);
+}
+#endif
+
+static struct nand_flash_dev *
+sddr09_get_cardinfo(struct us_data *us, unsigned char flags) {
+	struct nand_flash_dev *cardinfo;
+	unsigned char deviceID[4];
+	char blurbtxt[256];
+	int result;
+
+	US_DEBUGP("Reading capacity...\n");
+
+	result = sddr09_read_deviceID(us, deviceID);
+
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("Result of read_deviceID is %d\n", result);
+		printk("sddr09: could not read card info\n");
+		return NULL;
+	}
+
+	sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X",
+		deviceID[0], deviceID[1], deviceID[2], deviceID[3]);
+
+	/* Byte 0 is the manufacturer */
+	sprintf(blurbtxt + strlen(blurbtxt),
+		": Manuf. %s",
+		nand_flash_manufacturer(deviceID[0]));
+
+	/* Byte 1 is the device type */
+	cardinfo = nand_find_id(deviceID[1]);
+	if (cardinfo) {
+		/* MB or MiB? It is neither. A 16 MB card has
+		   17301504 raw bytes, of which 16384000 are
+		   usable for user data. */
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", %d MB", 1<<(cardinfo->chipshift - 20));
+	} else {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", type unrecognized");
+	}
+
+	/* Byte 2 is code to signal availability of 128-bit ID */
+	if (deviceID[2] == 0xa5) {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", 128-bit ID");
+	}
+
+	/* Byte 3 announces the availability of another read ID command */
+	if (deviceID[3] == 0xc0) {
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", extra cmd");
+	}
+
+	if (flags & SDDR09_WP)
+		sprintf(blurbtxt + strlen(blurbtxt),
+			", WP");
+
+	printk("%s\n", blurbtxt);
+
+	return cardinfo;
+}
+
+static int
+sddr09_read_map(struct us_data *us) {
+
+	struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra;
+	int numblocks, alloc_len, alloc_blocks;
+	int i, j, result;
+	unsigned char *buffer, *buffer_end, *ptr;
+	unsigned int lba, lbact;
+
+	if (!info->capacity)
+		return -1;
+
+	// size of a block is 1 << (blockshift + pageshift) bytes
+	// divide into the total capacity to get the number of blocks
+
+	numblocks = info->capacity >> (info->blockshift + info->pageshift);
+
+	// read 64 bytes for every block (actually 1 << CONTROL_SHIFT)
+	// but only use a 64 KB buffer
+	// buffer size used must be a multiple of (1 << CONTROL_SHIFT)
+#define SDDR09_READ_MAP_BUFSZ 65536
+
+	alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT);
+	alloc_len = (alloc_blocks << CONTROL_SHIFT);
+	buffer = kmalloc(alloc_len, GFP_NOIO);
+	if (buffer == NULL) {
+		printk("sddr09_read_map: out of memory\n");
+		result = -1;
+		goto done;
+	}
+	buffer_end = buffer + alloc_len;
+
+#undef SDDR09_READ_MAP_BUFSZ
+
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+	info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+	info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+
+	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+		printk("sddr09_read_map: out of memory\n");
+		result = -1;
+		goto done;
+	}
+
+	for (i = 0; i < numblocks; i++)
+		info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF;
+
+	/*
+	 * Define lba-pba translation table
+	 */
+
+	ptr = buffer_end;
+	for (i = 0; i < numblocks; i++) {
+		ptr += (1 << CONTROL_SHIFT);
+		if (ptr >= buffer_end) {
+			unsigned long address;
+
+			address = i << (info->pageshift + info->blockshift);
+			result = sddr09_read_control(
+				us, address>>1,
+				min(alloc_blocks, numblocks - i),
+				buffer, 0);
+			if (result != USB_STOR_TRANSPORT_GOOD) {
+				result = -1;
+				goto done;
+			}
+			ptr = buffer;
+		}
+
+		if (i == 0 || i == 1) {
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		/* special PBAs have control field 0^16 */
+		for (j = 0; j < 16; j++)
+			if (ptr[j] != 0)
+				goto nonz;
+		info->pba_to_lba[i] = UNUSABLE;
+		printk("sddr09: PBA %d has no logical mapping\n", i);
+		continue;
+
+	nonz:
+		/* unwritten PBAs have control field FF^16 */
+		for (j = 0; j < 16; j++)
+			if (ptr[j] != 0xff)
+				goto nonff;
+		continue;
+
+	nonff:
+		/* normal PBAs start with six FFs */
+		if (j < 6) {
+			printk("sddr09: PBA %d has no logical mapping: "
+			       "reserved area = %02X%02X%02X%02X "
+			       "data status %02X block status %02X\n",
+			       i, ptr[0], ptr[1], ptr[2], ptr[3],
+			       ptr[4], ptr[5]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		if ((ptr[6] >> 4) != 0x01) {
+			printk("sddr09: PBA %d has invalid address field "
+			       "%02X%02X/%02X%02X\n",
+			       i, ptr[6], ptr[7], ptr[11], ptr[12]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		/* check even parity */
+		if (parity[ptr[6] ^ ptr[7]]) {
+			printk("sddr09: Bad parity in LBA for block %d"
+			       " (%02X %02X)\n", i, ptr[6], ptr[7]);
+			info->pba_to_lba[i] = UNUSABLE;
+			continue;
+		}
+
+		lba = short_pack(ptr[7], ptr[6]);
+		lba = (lba & 0x07FF) >> 1;
+
+		/*
+		 * Every 1024 physical blocks ("zone"), the LBA numbers
+		 * go back to zero, but are within a higher block of LBA's.
+		 * Also, there is a maximum of 1000 LBA's per zone.
+		 * In other words, in PBA 1024-2047 you will find LBA 0-999
+		 * which are really LBA 1000-1999. This allows for 24 bad
+		 * or special physical blocks per zone.
+		 */
+
+		if (lba >= 1000) {
+			printk("sddr09: Bad low LBA %d for block %d\n",
+			       lba, i);
+			goto possibly_erase;
+		}
+
+		lba += 1000*(i/0x400);
+
+		if (info->lba_to_pba[lba] != UNDEF) {
+			printk("sddr09: LBA %d seen for PBA %d and %d\n",
+			       lba, info->lba_to_pba[lba], i);
+			goto possibly_erase;
+		}
+
+		info->pba_to_lba[i] = lba;
+		info->lba_to_pba[lba] = i;
+		continue;
+
+	possibly_erase:
+		if (erase_bad_lba_entries) {
+			unsigned long address;
+
+			address = (i << (info->pageshift + info->blockshift));
+			sddr09_erase(us, address>>1);
+			info->pba_to_lba[i] = UNDEF;
+		} else
+			info->pba_to_lba[i] = UNUSABLE;
+	}
+
+	/*
+	 * Approximate capacity. This is not entirely correct yet,
+	 * since a zone with less than 1000 usable pages leads to
+	 * missing LBAs. Especially if it is the last zone, some
+	 * LBAs can be past capacity.
+	 */
+	lbact = 0;
+	for (i = 0; i < numblocks; i += 1024) {
+		int ct = 0;
+
+		for (j = 0; j < 1024 && i+j < numblocks; j++) {
+			if (info->pba_to_lba[i+j] != UNUSABLE) {
+				if (ct >= 1000)
+					info->pba_to_lba[i+j] = SPARE;
+				else
+					ct++;
+			}
+		}
+		lbact += ct;
+	}
+	info->lbact = lbact;
+	US_DEBUGP("Found %d LBA's\n", lbact);
+	result = 0;
+
+ done:
+	if (result != 0) {
+		kfree(info->lba_to_pba);
+		kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+	}
+	kfree(buffer);
+	return result;
+}
+
+static void
+sddr09_card_info_destructor(void *extra) {
+	struct sddr09_card_info *info = (struct sddr09_card_info *)extra;
+
+	if (!info)
+		return;
+
+	kfree(info->lba_to_pba);
+	kfree(info->pba_to_lba);
+}
+
+static void
+sddr09_init_card_info(struct us_data *us) {
+	if (!us->extra) {
+		us->extra = kmalloc(sizeof(struct sddr09_card_info), GFP_NOIO);
+		if (us->extra) {
+			memset(us->extra, 0, sizeof(struct sddr09_card_info));
+			us->extra_destructor = sddr09_card_info_destructor;
+		}
+	}
+}
+
+/*
+ * This is needed at a very early stage. If this is not listed in the
+ * unusual devices list but called from here then LUN 0 of the combo reader
+ * is not recognized. But I do not know what precisely these calls do.
+ */
+int
+sddr09_init(struct us_data *us) {
+	int result;
+	unsigned char *data = us->iobuf;
+
+	result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_init: send_command fails\n");
+		return result;
+	}
+
+	US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+	// get 07 02
+
+	result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_init: 2nd send_command fails\n");
+		return result;
+	}
+
+	US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]);
+	// get 07 00
+
+	result = sddr09_request_sense(us, data, 18);
+	if (result == USB_STOR_TRANSPORT_GOOD && data[2] != 0) {
+		int j;
+		for (j=0; j<18; j++)
+			printk(" %02X", data[j]);
+		printk("\n");
+		// get 70 00 00 00 00 00 00 * 00 00 00 00 00 00
+		// 70: current command
+		// sense key 0, sense code 0, extd sense code 0
+		// additional transfer length * = sizeof(data) - 7
+		// Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00
+		// sense key 06, sense code 28: unit attention,
+		// not ready to ready transition
+	}
+
+	// test unit ready
+
+	return USB_STOR_TRANSPORT_GOOD;		/* not result */
+}
+
+/*
+ * Transport for the Sandisk SDDR-09
+ */
+int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	static unsigned char sensekey = 0, sensecode = 0;
+	static unsigned char havefakesense = 0;
+	int result, i;
+	unsigned char *ptr = us->iobuf;
+	unsigned long capacity;
+	unsigned int page, pages;
+
+	struct sddr09_card_info *info;
+
+	static unsigned char inquiry_response[8] = {
+		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	/* note: no block descriptor support */
+	static unsigned char mode_page_01[19] = {
+		0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00,
+		0x01, 0x0A,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	info = (struct sddr09_card_info *)us->extra;
+	if (!info) {
+		nand_init_ecc();
+		sddr09_init_card_info(us);
+		info = (struct sddr09_card_info *)us->extra;
+		if (!info)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) {
+		/* for a faked command, we have to follow with a faked sense */
+		memset(ptr, 0, 18);
+		ptr[0] = 0x70;
+		ptr[2] = sensekey;
+		ptr[7] = 11;
+		ptr[12] = sensecode;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+		sensekey = sensecode = havefakesense = 0;
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	havefakesense = 1;
+
+	/* Dummy up a response for INQUIRY since SDDR09 doesn't
+	   respond to INQUIRY commands */
+
+	if (srb->cmnd[0] == INQUIRY) {
+		memcpy(ptr, inquiry_response, 8);
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		struct nand_flash_dev *cardinfo;
+
+		sddr09_get_wp(us, info);	/* read WP bit */
+
+		cardinfo = sddr09_get_cardinfo(us, info->flags);
+		if (!cardinfo) {
+			/* probably no media */
+		init_error:
+			sensekey = 0x02;	/* not ready */
+			sensecode = 0x3a;	/* medium not present */
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		info->capacity = (1 << cardinfo->chipshift);
+		info->pageshift = cardinfo->pageshift;
+		info->pagesize = (1 << info->pageshift);
+		info->blockshift = cardinfo->blockshift;
+		info->blocksize = (1 << info->blockshift);
+		info->blockmask = info->blocksize - 1;
+
+		// map initialization, must follow get_cardinfo()
+		if (sddr09_read_map(us)) {
+			/* probably out of memory */
+			goto init_error;
+		}
+
+		// Report capacity
+
+		capacity = (info->lbact << info->blockshift) - 1;
+
+		((__be32 *) ptr)[0] = cpu_to_be32(capacity);
+
+		// Report page size
+
+		((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		int modepage = (srb->cmnd[2] & 0x3F);
+
+		/* They ask for the Read/Write error recovery page,
+		   or for all pages. */
+		/* %% We should check DBD %% */
+		if (modepage == 0x01 || modepage == 0x3F) {
+			US_DEBUGP("SDDR09: Dummy up request for "
+				  "mode page 0x%x\n", modepage);
+
+			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
+			((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2);
+			ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0;
+			usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		sensekey = 0x05;	/* illegal request */
+		sensecode = 0x24;	/* invalid field in CDB */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	havefakesense = 0;
+
+	if (srb->cmnd[0] == READ_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		US_DEBUGP("READ_10: read page %d pagect %d\n",
+			  page, pages);
+
+		return sddr09_read_data(us, page, pages);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		US_DEBUGP("WRITE_10: write page %d pagect %d\n",
+			  page, pages);
+
+		return sddr09_write_data(us, page, pages);
+	}
+
+	/* catch-all for all other commands, except
+	 * pass TEST_UNIT_READY and REQUEST_SENSE through
+	 */
+	if (srb->cmnd[0] != TEST_UNIT_READY &&
+	    srb->cmnd[0] != REQUEST_SENSE) {
+		sensekey = 0x05;	/* illegal request */
+		sensecode = 0x20;	/* invalid command */
+		havefakesense = 1;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	for (; srb->cmd_len<12; srb->cmd_len++)
+		srb->cmnd[srb->cmd_len] = 0;
+
+	srb->cmnd[1] = LUNBITS;
+
+	ptr[0] = 0;
+	for (i=0; i<12; i++)
+		sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]);
+
+	US_DEBUGP("SDDR09: Send control for command %s\n", ptr);
+
+	result = sddr09_send_scsi_command(us, srb->cmnd, 12);
+	if (result != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("sddr09_transport: sddr09_send_scsi_command "
+			  "returns %d\n", result);
+		return result;
+	}
+
+	if (srb->request_bufflen == 0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	if (srb->sc_data_direction == DMA_TO_DEVICE ||
+	    srb->sc_data_direction == DMA_FROM_DEVICE) {
+		unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE)
+				? us->send_bulk_pipe : us->recv_bulk_pipe;
+
+		US_DEBUGP("SDDR09: %s %d bytes\n",
+			  (srb->sc_data_direction == DMA_TO_DEVICE) ?
+			  "sending" : "receiving",
+			  srb->request_bufflen);
+
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer,
+					srb->request_bufflen,
+					srb->use_sg, &srb->resid);
+
+		return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+	} 
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
new file mode 100644
index 0000000..c9d78d6
--- /dev/null
+++ b/drivers/usb/storage/sddr09.h
@@ -0,0 +1,48 @@
+/* Driver for SanDisk SDDR-09 SmartMedia reader
+ * Header File
+ *
+ * $Id: sddr09.h,v 1.5 2000/08/25 00:13:51 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Robert Baruch (autophile@dol.net)
+ *   (c) 2002 Andries Brouwer (aeb@cwi.nl)
+ *
+ * See sddr09.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_SHUTTLE_EUSB_SDDR09_H
+#define _USB_SHUTTLE_EUSB_SDDR09_H
+
+/* Sandisk SDDR-09 stuff */
+
+extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+struct sddr09_card_info {
+	unsigned long	capacity;	/* Size of card in bytes */
+	int		pagesize;	/* Size of page in bytes */
+	int		pageshift;	/* log2 of pagesize */
+	int		blocksize;	/* Size of block in pages */
+	int		blockshift;	/* log2 of blocksize */
+	int		blockmask;	/* 2^blockshift - 1 */
+	int		*lba_to_pba;	/* logical to physical map */
+	int		*pba_to_lba;	/* physical to logical map */
+	int		lbact;		/* number of available pages */
+	int		flags;
+#define	SDDR09_WP	1		/* write protected */
+};
+
+#endif
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
new file mode 100644
index 0000000..229ca18
--- /dev/null
+++ b/drivers/usb/storage/sddr55.c
@@ -0,0 +1,938 @@
+/* Driver for SanDisk SDDR-55 SmartMedia reader
+ *
+ * $Id:$
+ *
+ * SDDR55 driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Simon Munton
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "sddr55.h"
+
+
+#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+#define PAGESIZE  512
+
+#define set_sense_info(sk, asc, ascq)	\
+    do {				\
+	info->sense_data[2] = sk;	\
+	info->sense_data[12] = asc;	\
+	info->sense_data[13] = ascq;	\
+	} while (0)
+
+
+struct sddr55_card_info {
+	unsigned long	capacity;	/* Size of card in bytes */
+	int		max_log_blks;	/* maximum number of logical blocks */
+	int		pageshift;	/* log2 of pagesize */
+	int		smallpageshift;	/* 1 if pagesize == 256 */
+	int		blocksize;	/* Size of block in pages */
+	int		blockshift;	/* log2 of blocksize */
+	int		blockmask;	/* 2^blockshift - 1 */
+	int		read_only;	/* non zero if card is write protected */
+	int		force_read_only;	/* non zero if we find a map error*/
+	int		*lba_to_pba;	/* logical to physical map */
+	int		*pba_to_lba;	/* physical to logical map */
+	int		fatal_error;	/* set if we detect something nasty */
+	unsigned long 	last_access;	/* number of jiffies since we last talked to device */
+	unsigned char   sense_data[18];
+};
+
+
+#define NOT_ALLOCATED		0xffffffff
+#define BAD_BLOCK		0xffff
+#define CIS_BLOCK		0x400
+#define UNUSED_BLOCK		0x3ff
+
+static int
+sddr55_bulk_transport(struct us_data *us, int direction,
+		      unsigned char *data, unsigned int len) {
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
+			us->recv_bulk_pipe : us->send_bulk_pipe;
+
+	if (!len)
+		return USB_STOR_XFER_GOOD;
+	info->last_access = jiffies;
+	return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL);
+}
+
+/* check if card inserted, if there is, update read_only status
+ * return non zero if no card
+ */
+
+static int sddr55_status(struct us_data *us)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+	unsigned char *status = us->iobuf;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	/* send command */
+	memset(command, 0, 8);
+	command[5] = 0xB0;
+	command[7] = 0x80;
+	result = sddr55_bulk_transport(us,
+		DMA_TO_DEVICE, command, 8);
+
+	US_DEBUGP("Result for send_command in status %d\n",
+		result);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	result = sddr55_bulk_transport(us,
+		DMA_FROM_DEVICE, status,	4);
+
+	/* expect to get short transfer if no card fitted */
+	if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) {
+		/* had a short transfer, no card inserted, free map memory */
+		if (info->lba_to_pba)
+			kfree(info->lba_to_pba);
+		if (info->pba_to_lba)
+			kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+
+		info->fatal_error = 0;
+		info->force_read_only = 0;
+
+		set_sense_info (2, 0x3a, 0);	/* not ready, medium not present */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (result != USB_STOR_XFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+	
+	/* check write protect status */
+	info->read_only = (status[0] & 0x20);
+
+	/* now read status */
+	result = sddr55_bulk_transport(us,
+		DMA_FROM_DEVICE, status,	2);
+
+	if (result != USB_STOR_XFER_GOOD) {
+		set_sense_info (4, 0, 0);	/* hardware error */
+	}
+
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_FAILED);
+}
+
+
+static int sddr55_read_data(struct us_data *us,
+		unsigned int lba,
+		unsigned int page,
+		unsigned short sectors) {
+
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *command = us->iobuf;
+	unsigned char *status = us->iobuf;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned char *buffer;
+
+	unsigned int pba;
+	unsigned long address;
+
+	unsigned short pages;
+	unsigned int len, index, offset;
+
+	// Since we only read in one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
+			info->smallpageshift) * PAGESIZE;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR; /* out of memory */
+	index = offset = 0;
+
+	while (sectors>0) {
+
+		/* have we got to end? */
+		if (lba >= info->max_log_blks)
+			break;
+
+		pba = info->lba_to_pba[lba];
+
+		// Read as many sectors as possible in this block
+
+		pages = min((unsigned int) sectors << info->smallpageshift,
+				info->blocksize - page);
+		len = pages << info->pageshift;
+
+		US_DEBUGP("Read %02X pages, from PBA %04X"
+			" (LBA %04X) page %02X\n",
+			pages, pba, lba, page);
+
+		if (pba == NOT_ALLOCATED) {
+			/* no pba for this lba, fill with zeroes */
+			memset (buffer, 0, len);
+		} else {
+
+			address = (pba << info->blockshift) + page;
+
+			command[0] = 0;
+			command[1] = LSB_of(address>>16);
+			command[2] = LSB_of(address>>8);
+			command[3] = LSB_of(address);
+
+			command[4] = 0;
+			command[5] = 0xB0;
+			command[6] = LSB_of(pages << (1 - info->smallpageshift));
+			command[7] = 0x85;
+
+			/* send command */
+			result = sddr55_bulk_transport(us,
+				DMA_TO_DEVICE, command, 8);
+
+			US_DEBUGP("Result for send_command in read_data %d\n",
+				result);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto leave;
+			}
+
+			/* read data */
+			result = sddr55_bulk_transport(us,
+				DMA_FROM_DEVICE, buffer, len);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto leave;
+			}
+
+			/* now read status */
+			result = sddr55_bulk_transport(us,
+				DMA_FROM_DEVICE, status, 2);
+
+			if (result != USB_STOR_XFER_GOOD) {
+				result = USB_STOR_TRANSPORT_ERROR;
+				goto leave;
+			}
+
+			/* check status for error */
+			if (status[0] == 0xff && status[1] == 0x4) {
+				set_sense_info (3, 0x11, 0);
+				result = USB_STOR_TRANSPORT_FAILED;
+				goto leave;
+			}
+		}
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&index, &offset, TO_XFER_BUF);
+
+		page = 0;
+		lba++;
+		sectors -= pages >> info->smallpageshift;
+	}
+
+	result = USB_STOR_TRANSPORT_GOOD;
+
+leave:
+	kfree(buffer);
+
+	return result;
+}
+
+static int sddr55_write_data(struct us_data *us,
+		unsigned int lba,
+		unsigned int page,
+		unsigned short sectors) {
+
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *command = us->iobuf;
+	unsigned char *status = us->iobuf;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned char *buffer;
+
+	unsigned int pba;
+	unsigned int new_pba;
+	unsigned long address;
+
+	unsigned short pages;
+	int i;
+	unsigned int len, index, offset;
+
+	/* check if we are allowed to write */
+	if (info->read_only || info->force_read_only) {
+		set_sense_info (7, 0x27, 0);	/* read only */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	// Since we only write one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = min((unsigned int) sectors, (unsigned int) info->blocksize >>
+			info->smallpageshift) * PAGESIZE;
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+	index = offset = 0;
+
+	while (sectors > 0) {
+
+		/* have we got to end? */
+		if (lba >= info->max_log_blks)
+			break;
+
+		pba = info->lba_to_pba[lba];
+
+		// Write as many sectors as possible in this block
+
+		pages = min((unsigned int) sectors << info->smallpageshift,
+				info->blocksize - page);
+		len = pages << info->pageshift;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+				&index, &offset, FROM_XFER_BUF);
+
+		US_DEBUGP("Write %02X pages, to PBA %04X"
+			" (LBA %04X) page %02X\n",
+			pages, pba, lba, page);
+			
+		command[4] = 0;
+
+		if (pba == NOT_ALLOCATED) {
+			/* no pba allocated for this lba, find a free pba to use */
+
+			int max_pba = (info->max_log_blks / 250 ) * 256;
+			int found_count = 0;
+			int found_pba = -1;
+
+			/* set pba to first block in zone lba is in */
+			pba = (lba / 1000) * 1024;
+
+			US_DEBUGP("No PBA for LBA %04X\n",lba);
+
+			if (max_pba > 1024)
+				max_pba = 1024;
+
+			/*
+			 * Scan through the map looking for an unused block
+			 * leave 16 unused blocks at start (or as many as
+			 * possible) since the sddr55 seems to reuse a used
+			 * block when it shouldn't if we don't leave space.
+			 */
+			for (i = 0; i < max_pba; i++, pba++) {
+				if (info->pba_to_lba[pba] == UNUSED_BLOCK) {
+					found_pba = pba;
+					if (found_count++ > 16)
+						break;
+				}
+			}
+
+			pba = found_pba;
+
+			if (pba == -1) {
+				/* oh dear */
+				US_DEBUGP("Couldn't find unallocated block\n");
+
+				set_sense_info (3, 0x31, 0);	/* medium error */
+				result = USB_STOR_TRANSPORT_FAILED;
+				goto leave;
+			}
+
+			US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba);
+
+			/* set writing to unallocated block flag */
+			command[4] = 0x40;
+		}
+
+		address = (pba << info->blockshift) + page;
+
+		command[1] = LSB_of(address>>16);
+		command[2] = LSB_of(address>>8); 
+		command[3] = LSB_of(address);
+
+		/* set the lba into the command, modulo 1000 */
+		command[0] = LSB_of(lba % 1000);
+		command[6] = MSB_of(lba % 1000);
+
+		command[4] |= LSB_of(pages >> info->smallpageshift);
+		command[5] = 0xB0;
+		command[7] = 0x86;
+
+		/* send command */
+		result = sddr55_bulk_transport(us,
+			DMA_TO_DEVICE, command, 8);
+
+		if (result != USB_STOR_XFER_GOOD) {
+			US_DEBUGP("Result for send_command in write_data %d\n",
+			result);
+
+			/* set_sense_info is superfluous here? */
+			set_sense_info (3, 0x3, 0);/* peripheral write error */
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		/* send the data */
+		result = sddr55_bulk_transport(us,
+			DMA_TO_DEVICE, buffer, len);
+
+		if (result != USB_STOR_XFER_GOOD) {
+			US_DEBUGP("Result for send_data in write_data %d\n",
+				  result);
+
+			/* set_sense_info is superfluous here? */
+			set_sense_info (3, 0x3, 0);/* peripheral write error */
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		/* now read status */
+		result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6);
+
+		if (result != USB_STOR_XFER_GOOD) {
+			US_DEBUGP("Result for get_status in write_data %d\n",
+				  result);
+
+			/* set_sense_info is superfluous here? */
+			set_sense_info (3, 0x3, 0);/* peripheral write error */
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		new_pba = (status[3] + (status[4] << 8) + (status[5] << 16))
+						  >> info->blockshift;
+
+		/* check status for error */
+		if (status[0] == 0xff && status[1] == 0x4) {
+			info->pba_to_lba[new_pba] = BAD_BLOCK;
+
+			set_sense_info (3, 0x0c, 0);
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n",
+			lba, pba, new_pba);
+
+		/* update the lba<->pba maps, note new_pba might be the same as pba */
+		info->lba_to_pba[lba] = new_pba;
+		info->pba_to_lba[pba] = UNUSED_BLOCK;
+
+		/* check that new_pba wasn't already being used */
+		if (info->pba_to_lba[new_pba] != UNUSED_BLOCK) {
+			printk(KERN_ERR "sddr55 error: new PBA %04X already in use for LBA %04X\n",
+				new_pba, info->pba_to_lba[new_pba]);
+			info->fatal_error = 1;
+			set_sense_info (3, 0x31, 0);
+			result = USB_STOR_TRANSPORT_FAILED;
+			goto leave;
+		}
+
+		/* update the pba<->lba maps for new_pba */
+		info->pba_to_lba[new_pba] = lba % 1000;
+
+		page = 0;
+		lba++;
+		sectors -= pages >> info->smallpageshift;
+	}
+	result = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(buffer);
+	return result;
+}
+
+static int sddr55_read_deviceID(struct us_data *us,
+		unsigned char *manufacturerID,
+		unsigned char *deviceID) {
+
+	int result;
+	unsigned char *command = us->iobuf;
+	unsigned char *content = us->iobuf;
+
+	memset(command, 0, 8);
+	command[5] = 0xB0;
+	command[7] = 0x84;
+	result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
+
+	US_DEBUGP("Result of send_control for device ID is %d\n",
+		result);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = sddr55_bulk_transport(us,
+		DMA_FROM_DEVICE, content, 4);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	*manufacturerID = content[0];
+	*deviceID = content[1];
+
+	if (content[0] != 0xff)	{
+    		result = sddr55_bulk_transport(us,
+			DMA_FROM_DEVICE, content, 2);
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+int sddr55_reset(struct us_data *us) {
+	return 0;
+}
+
+
+static unsigned long sddr55_get_capacity(struct us_data *us) {
+
+	unsigned char manufacturerID;
+	unsigned char deviceID;
+	int result;
+	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+
+	US_DEBUGP("Reading capacity...\n");
+
+	result = sddr55_read_deviceID(us,
+		&manufacturerID,
+		&deviceID);
+
+	US_DEBUGP("Result of read_deviceID is %d\n",
+		result);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return 0;
+
+	US_DEBUGP("Device ID = %02X\n", deviceID);
+	US_DEBUGP("Manuf  ID = %02X\n", manufacturerID);
+
+	info->pageshift = 9;
+	info->smallpageshift = 0;
+	info->blocksize = 16;
+	info->blockshift = 4;
+	info->blockmask = 15;
+
+	switch (deviceID) {
+
+	case 0x6e: // 1MB
+	case 0xe8:
+	case 0xec:
+		info->pageshift = 8;
+		info->smallpageshift = 1;
+		return 0x00100000;
+
+	case 0xea: // 2MB
+	case 0x64:
+		info->pageshift = 8;
+		info->smallpageshift = 1;
+	case 0x5d: // 5d is a ROM card with pagesize 512.
+		return 0x00200000;
+
+	case 0xe3: // 4MB
+	case 0xe5:
+	case 0x6b:
+	case 0xd5:
+		return 0x00400000;
+
+	case 0xe6: // 8MB
+	case 0xd6:
+		return 0x00800000;
+
+	case 0x73: // 16MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x01000000;
+
+	case 0x75: // 32MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x02000000;
+
+	case 0x76: // 64MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x04000000;
+
+	case 0x79: // 128MB
+		info->blocksize = 32;
+		info->blockshift = 5;
+		info->blockmask = 31;
+		return 0x08000000;
+
+	default: // unknown
+		return 0;
+
+	}
+}
+
+static int sddr55_read_map(struct us_data *us) {
+
+	struct sddr55_card_info *info = (struct sddr55_card_info *)(us->extra);
+	int numblocks;
+	unsigned char *buffer;
+	unsigned char *command = us->iobuf;
+	int i;
+	unsigned short lba;
+	unsigned short max_lba;
+	int result;
+
+	if (!info->capacity)
+		return -1;
+
+	numblocks = info->capacity >> (info->blockshift + info->pageshift);
+	
+	buffer = kmalloc( numblocks * 2, GFP_NOIO );
+	
+	if (!buffer)
+		return -1;
+
+	memset(command, 0, 8);
+	command[5] = 0xB0;
+	command[6] = numblocks * 2 / 256;
+	command[7] = 0x8A;
+
+	result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8);
+
+	if ( result != USB_STOR_XFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2);
+
+	if ( result != USB_STOR_XFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2);
+
+	if ( result != USB_STOR_XFER_GOOD) {
+		kfree (buffer);
+		return -1;
+	}
+
+	if (info->lba_to_pba)
+		kfree(info->lba_to_pba);
+	if (info->pba_to_lba)
+		kfree(info->pba_to_lba);
+	info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+	info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO);
+
+	if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) {
+		if (info->lba_to_pba != NULL)
+			kfree(info->lba_to_pba);
+		if (info->pba_to_lba != NULL)
+			kfree(info->pba_to_lba);
+		info->lba_to_pba = NULL;
+		info->pba_to_lba = NULL;
+		kfree(buffer);
+		return -1;
+	}
+
+	memset(info->lba_to_pba, 0xff, numblocks*sizeof(int));
+	memset(info->pba_to_lba, 0xff, numblocks*sizeof(int));
+
+	/* set maximum lba */
+	max_lba = info->max_log_blks;
+	if (max_lba > 1000)
+		max_lba = 1000;
+
+	// Each block is 64 bytes of control data, so block i is located in
+	// scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
+
+	for (i=0; i<numblocks; i++) {
+		int zone = i / 1024;
+
+		lba = short_pack(buffer[i * 2], buffer[i * 2 + 1]);
+
+			/* Every 1024 physical blocks ("zone"), the LBA numbers
+			 * go back to zero, but are within a higher
+			 * block of LBA's. Also, there is a maximum of
+			 * 1000 LBA's per zone. In other words, in PBA
+			 * 1024-2047 you will find LBA 0-999 which are
+			 * really LBA 1000-1999. Yes, this wastes 24
+			 * physical blocks per zone. Go figure. 
+			 * These devices can have blocks go bad, so there
+			 * are 24 spare blocks to use when blocks do go bad.
+			 */
+
+			/* SDDR55 returns 0xffff for a bad block, and 0x400 for the 
+			 * CIS block. (Is this true for cards 8MB or less??)
+			 * Record these in the physical to logical map
+			 */ 
+
+		info->pba_to_lba[i] = lba;
+
+		if (lba >= max_lba) {
+			continue;
+		}
+		
+		if (info->lba_to_pba[lba + zone * 1000] != NOT_ALLOCATED &&
+		    !info->force_read_only) {
+			printk("sddr55: map inconsistency at LBA %04X\n", lba + zone * 1000);
+			info->force_read_only = 1;
+		}
+
+		if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
+			US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
+
+		info->lba_to_pba[lba + zone * 1000] = i;
+	}
+
+	kfree(buffer);
+	return 0;
+}
+
+
+static void sddr55_card_info_destructor(void *extra) {
+	struct sddr55_card_info *info = (struct sddr55_card_info *)extra;
+
+	if (!extra)
+		return;
+
+	if (info->lba_to_pba)
+		kfree(info->lba_to_pba);
+	if (info->pba_to_lba)
+		kfree(info->pba_to_lba);
+}
+
+
+/*
+ * Transport for the Sandisk SDDR-55
+ */
+int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int result;
+	static unsigned char inquiry_response[8] = {
+		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
+	};
+ 	// write-protected for now, no block descriptor support
+	static unsigned char mode_page_01[20] = {
+		0x0, 0x12, 0x00, 0x80, 0x0, 0x0, 0x0, 0x0,
+		0x01, 0x0A,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+	unsigned char *ptr = us->iobuf;
+	unsigned long capacity;
+	unsigned int lba;
+	unsigned int pba;
+	unsigned int page;
+	unsigned short pages;
+	struct sddr55_card_info *info;
+
+	if (!us->extra) {
+		us->extra = kmalloc(
+			sizeof(struct sddr55_card_info), GFP_NOIO);
+		if (!us->extra)
+			return USB_STOR_TRANSPORT_ERROR;
+		memset(us->extra, 0, sizeof(struct sddr55_card_info));
+		us->extra_destructor = sddr55_card_info_destructor;
+	}
+
+	info = (struct sddr55_card_info *)(us->extra);
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]);
+
+		memcpy (ptr, info->sense_data, sizeof info->sense_data);
+		ptr[0] = 0x70;
+		ptr[7] = 11;
+		usb_stor_set_xfer_buf (ptr, sizeof info->sense_data, srb);
+		memset (info->sense_data, 0, sizeof info->sense_data);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	memset (info->sense_data, 0, sizeof info->sense_data);
+
+	/* Dummy up a response for INQUIRY since SDDR55 doesn't
+	   respond to INQUIRY commands */
+
+	if (srb->cmnd[0] == INQUIRY) {
+		memcpy(ptr, inquiry_response, 8);
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	/* only check card status if the map isn't allocated, ie no card seen yet
+	 * or if it's been over half a second since we last accessed it
+	 */
+	if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) {
+
+		/* check to see if a card is fitted */
+		result = sddr55_status (us);
+		if (result) {
+			result = sddr55_status (us);
+			if (!result) {
+			set_sense_info (6, 0x28, 0);	/* new media, set unit attention, not ready to ready */
+			}
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+	}
+
+	/* if we detected a problem with the map when writing,
+	   don't allow any more access */
+	if (info->fatal_error) {
+
+		set_sense_info (3, 0x31, 0);
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+
+		capacity = sddr55_get_capacity(us);
+
+		if (!capacity) {
+			set_sense_info (3, 0x30, 0); /* incompatible medium */
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		info->capacity = capacity;
+
+		/* figure out the maximum logical block number, allowing for
+		 * the fact that only 250 out of every 256 are used */
+		info->max_log_blks = ((info->capacity >> (info->pageshift + info->blockshift)) / 256) * 250;
+
+		/* Last page in the card, adjust as we only use 250 out of
+		 * every 256 pages */
+		capacity = (capacity / 256) * 250;
+
+		capacity /= PAGESIZE;
+		capacity--;
+
+		((__be32 *) ptr)[0] = cpu_to_be32(capacity);
+		((__be32 *) ptr)[1] = cpu_to_be32(PAGESIZE);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		sddr55_read_map(us);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+
+		memcpy(ptr, mode_page_01, sizeof mode_page_01);
+		ptr[3] = (info->read_only || info->force_read_only) ? 0x80 : 0;
+		usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb);
+
+		if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
+			US_DEBUGP(
+			  "SDDR55: Dummy up request for mode page 1\n");
+			return USB_STOR_TRANSPORT_GOOD;
+
+		} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
+			US_DEBUGP(
+			  "SDDR55: Dummy up request for all mode pages\n");
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		set_sense_info (5, 0x24, 0);	/* invalid field in command */
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+
+		US_DEBUGP(
+		  "SDDR55: %s medium removal. Not that I can do"
+		  " anything about it...\n",
+		  (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+
+		return USB_STOR_TRANSPORT_GOOD;
+
+	}
+
+	if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) {
+
+		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
+		page <<= 16;
+		page |= short_pack(srb->cmnd[5], srb->cmnd[4]);
+		pages = short_pack(srb->cmnd[8], srb->cmnd[7]);
+
+		page <<= info->smallpageshift;
+
+		// convert page to block and page-within-block
+
+		lba = page >> info->blockshift;
+		page = page & info->blockmask;
+
+		// locate physical block corresponding to logical block
+
+		if (lba >= info->max_log_blks) {
+
+			US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
+			  "block %04X\n", lba, info->max_log_blks-1);
+
+			set_sense_info (5, 0x24, 0);	/* invalid field in command */
+
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		pba = info->lba_to_pba[lba];
+
+		if (srb->cmnd[0] == WRITE_10) {
+			US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X"
+				" pages %d\n",
+				pba, lba, page, pages);
+
+			return sddr55_write_data(us, lba, page, pages);
+		} else {
+			US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X"
+				" pages %d\n",
+				pba, lba, page, pages);
+
+			return sddr55_read_data(us, lba, page, pages);
+		}
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == START_STOP) {
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	set_sense_info (5, 0x20, 0);	/* illegal command */
+
+	return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer?
+}
+
diff --git a/drivers/usb/storage/sddr55.h b/drivers/usb/storage/sddr55.h
new file mode 100644
index 0000000..d6bd32f
--- /dev/null
+++ b/drivers/usb/storage/sddr55.h
@@ -0,0 +1,34 @@
+/* Driver for SanDisk SDDR-55 SmartMedia reader
+ * Header File
+ *
+ * $Id:$
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Simon Munton
+ *
+ * See sddr55.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_SHUTTLE_EUSB_SDDR55_H
+#define _USB_SHUTTLE_EUSB_SDDR55_H
+
+/* Sandisk SDDR-55 stuff */
+
+extern int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int sddr55_reset(struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
new file mode 100644
index 0000000..7eff03d
--- /dev/null
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -0,0 +1,1712 @@
+/* Driver for SCM Microsystems USB-ATAPI cable
+ *
+ * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
+ *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * Developed with the assistance of:
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Flash support based on earlier work by:
+ *   (c) 2002 Thomas Kreiling <usbdev@sm04.de>
+ *
+ * Many originally ATAPI devices were slightly modified to meet the USB
+ * market by using some kind of translation from ATAPI to USB on the host,
+ * and the peripheral would translate from USB back to ATAPI.
+ *
+ * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only, 
+ * which does the USB-to-ATAPI conversion.  By obtaining the data sheet on
+ * their device under nondisclosure agreement, I have been able to write
+ * this driver for Linux.
+ *
+ * The chip used in the device can also be used for EPP and ISA translation
+ * as well. This driver is only guaranteed to work with the ATAPI
+ * translation.
+ *
+ * See the Kconfig help text for a list of devices known to be supported by
+ * this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/cdrom.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "shuttle_usbat.h"
+
+#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+static int transferred = 0;
+
+static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
+static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+/*
+ * Convenience function to produce an ATAPI read/write sectors command
+ * Use cmd=0x20 for read, cmd=0x30 for write
+ */
+static void usbat_pack_atapi_sector_cmd(unsigned char *buf,
+					unsigned char thistime,
+					u32 sector, unsigned char cmd)
+{
+	buf[0] = 0;
+	buf[1] = thistime;
+	buf[2] = sector & 0xFF;
+	buf[3] = (sector >>  8) & 0xFF;
+	buf[4] = (sector >> 16) & 0xFF;
+	buf[5] = 0xE0 | ((sector >> 24) & 0x0F);
+	buf[6] = cmd;
+}
+
+/*
+ * Convenience function to get the device type (flash or hp8200)
+ */
+static int usbat_get_device_type(struct us_data *us)
+{
+	return ((struct usbat_info*)us->extra)->devicetype;
+}
+
+/*
+ * Read a register from the device
+ */
+static int usbat_read(struct us_data *us,
+		      unsigned char access,
+		      unsigned char reg,
+		      unsigned char *content)
+{
+	return usb_stor_ctrl_transfer(us,
+		us->recv_ctrl_pipe,
+		access | USBAT_CMD_READ_REG,
+		0xC0,
+		(u16)reg,
+		0,
+		content,
+		1);
+}
+
+/*
+ * Write to a register on the device
+ */
+static int usbat_write(struct us_data *us,
+		       unsigned char access,
+		       unsigned char reg,
+		       unsigned char content)
+{
+	return usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
+		access | USBAT_CMD_WRITE_REG,
+		0x40,
+		short_pack(reg, content),
+		0,
+		NULL,
+		0);
+}
+
+/*
+ * Convenience function to perform a bulk read
+ */
+static int usbat_bulk_read(struct us_data *us,
+							 unsigned char *data,
+							 unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("usbat_bulk_read: len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL);
+}
+
+/*
+ * Convenience function to perform a bulk write
+ */
+static int usbat_bulk_write(struct us_data *us,
+							unsigned char *data,
+							unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_XFER_GOOD;
+
+	US_DEBUGP("usbat_bulk_write:  len = %d\n", len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL);
+}
+
+/*
+ * Some USBAT-specific commands can only be executed over a command transport
+ * This transport allows one (len=8) or two (len=16) vendor-specific commands
+ * to be executed.
+ */
+static int usbat_execute_command(struct us_data *us,
+								 unsigned char *commands,
+								 unsigned int len)
+{
+	return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+								  USBAT_CMD_EXEC_CMD, 0x40, 0, 0,
+								  commands, len);
+}
+
+/*
+ * Read the status register
+ */
+static int usbat_get_status(struct us_data *us, unsigned char *status)
+{
+	int rc;
+	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status);
+
+	US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status));
+	return rc;
+}
+
+/*
+ * Check the device status
+ */
+static int usbat_check_status(struct us_data *us)
+{
+	unsigned char *reply = us->iobuf;
+	int rc;
+
+	if (!us)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_get_status(us, reply);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	if (*reply & 0x01 && *reply != 0x51) // error/check condition (0x51 is ok)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	if (*reply & 0x20) // device fault
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Stores critical information in internal registers in prepartion for the execution
+ * of a conditional usbat_read_blocks or usbat_write_blocks call.
+ */
+static int usbat_set_shuttle_features(struct us_data *us,
+				      unsigned char external_trigger,
+				      unsigned char epp_control,
+				      unsigned char mask_byte,
+				      unsigned char test_pattern,
+				      unsigned char subcountH,
+				      unsigned char subcountL)
+{
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0x40;
+	command[1] = USBAT_CMD_SET_FEAT;
+
+	// The only bit relevant to ATA access is bit 6
+	// which defines 8 bit data access (set) or 16 bit (unset)
+	command[2] = epp_control;
+
+	// If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
+	// ET1 and ET2 define an external event to be checked for on event of a
+	// _read_blocks or _write_blocks operation. The read/write will not take
+	// place unless the defined trigger signal is active.
+	command[3] = external_trigger;
+
+	// The resultant byte of the mask operation (see mask_byte) is compared for
+	// equivalence with this test pattern. If equal, the read/write will take
+	// place.
+	command[4] = test_pattern;
+
+	// This value is logically ANDed with the status register field specified
+	// in the read/write command.
+	command[5] = mask_byte;
+
+	// If ALQ is set in the qualifier, this field contains the address of the
+	// registers where the byte count should be read for transferring the data.
+	// If ALQ is not set, then this field contains the number of bytes to be
+	// transferred.
+	command[6] = subcountL;
+	command[7] = subcountH;
+
+	return usbat_execute_command(us, command, 8);
+}
+
+/*
+ * Block, waiting for an ATA device to become not busy or to report
+ * an error condition.
+ */
+static int usbat_wait_not_busy(struct us_data *us, int minutes)
+{
+	int i;
+	int result;
+	unsigned char *status = us->iobuf;
+
+	/* Synchronizing cache on a CDR could take a heck of a long time,
+	 * but probably not more than 10 minutes or so. On the other hand,
+	 * doing a full blank on a CDRW at speed 1 will take about 75
+	 * minutes!
+	 */
+
+	for (i=0; i<1200+minutes*60; i++) {
+
+ 		result = usbat_get_status(us, status);
+
+		if (result!=USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		if (*status & 0x01) { // check condition
+			result = usbat_read(us, USBAT_ATA, 0x10, status);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+		if (*status & 0x20) // device fault
+			return USB_STOR_TRANSPORT_FAILED;
+
+		if ((*status & 0x80)==0x00) { // not busy
+			US_DEBUGP("Waited not busy for %d steps\n", i);
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		if (i<500)
+			msleep(10); // 5 seconds
+		else if (i<700)
+			msleep(50); // 10 seconds
+		else if (i<1200)
+			msleep(100); // 50 seconds
+		else
+			msleep(1000); // X minutes
+	}
+
+	US_DEBUGP("Waited not busy for %d minutes, timing out.\n",
+		minutes);
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Read block data from the data register
+ */
+static int usbat_read_block(struct us_data *us,
+			    unsigned char *content,
+			    unsigned short len)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	command[0] = 0xC0;
+	command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = usbat_bulk_read(us, content, len);
+	return (result == USB_STOR_XFER_GOOD ?
+			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
+}
+
+/*
+ * Write block data via the data register
+ */
+static int usbat_write_block(struct us_data *us,
+			     unsigned char access,
+			     unsigned char *content,
+			     unsigned short len,
+			     int minutes)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	command[0] = 0x40;
+	command[1] = access | USBAT_CMD_WRITE_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	result = usbat_execute_command(us, command, 8);
+
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	result = usbat_bulk_write(us, content, len);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return usbat_wait_not_busy(us, minutes);
+}
+
+/*
+ * Process read and write requests
+ */
+static int usbat_hp8200e_rw_block_test(struct us_data *us,
+				       unsigned char access,
+				       unsigned char *registers,
+				       unsigned char *data_out,
+				       unsigned short num_registers,
+				       unsigned char data_reg,
+				       unsigned char status_reg,
+				       unsigned char timeout,
+				       unsigned char qualifier,
+				       int direction,
+				       unsigned char *content,
+				       unsigned short len,
+				       int use_sg,
+				       int minutes)
+{
+	int result;
+	unsigned int pipe = (direction == DMA_FROM_DEVICE) ?
+			us->recv_bulk_pipe : us->send_bulk_pipe;
+
+	unsigned char *command = us->iobuf;
+	int i, j;
+	int cmdlen;
+	unsigned char *data = us->iobuf;
+	unsigned char *status = us->iobuf;
+
+	BUG_ON(num_registers > US_IOBUF_SIZE/2);
+
+	for (i=0; i<20; i++) {
+
+		/*
+		 * The first time we send the full command, which consists
+		 * of downloading the SCSI command followed by downloading
+		 * the data via a write-and-test.  Any other time we only
+		 * send the command to download the data -- the SCSI command
+		 * is still 'active' in some sense in the device.
+		 * 
+		 * We're only going to try sending the data 10 times. After
+		 * that, we just return a failure.
+		 */
+
+		if (i==0) {
+			cmdlen = 16;
+			// Write to multiple registers
+			// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
+			// but that's what came out of the trace every single time.
+			command[0] = 0x40;
+			command[1] = access | USBAT_CMD_WRITE_REGS;
+			command[2] = 0x07;
+			command[3] = 0x17;
+			command[4] = 0xFC;
+			command[5] = 0xE7;
+			command[6] = LSB_of(num_registers*2);
+			command[7] = MSB_of(num_registers*2);
+		} else
+			cmdlen = 8;
+
+		// Conditionally read or write blocks
+		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);
+		command[cmdlen-7] = access |
+				(direction==DMA_TO_DEVICE ?
+				 USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK);
+		command[cmdlen-6] = data_reg;
+		command[cmdlen-5] = status_reg;
+		command[cmdlen-4] = timeout;
+		command[cmdlen-3] = qualifier;
+		command[cmdlen-2] = LSB_of(len);
+		command[cmdlen-1] = MSB_of(len);
+
+		result = usbat_execute_command(us, command, cmdlen);
+
+		if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (i==0) {
+
+			for (j=0; j<num_registers; j++) {
+				data[j<<1] = registers[j];
+				data[1+(j<<1)] = data_out[j];
+			}
+
+			result = usbat_bulk_write(us, data, num_registers*2);
+			if (result != USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
+
+		}
+
+
+		//US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n",
+		//	direction == DMA_TO_DEVICE ? "out" : "in",
+		//	len, use_sg);
+
+		result = usb_stor_bulk_transfer_sg(us,
+			pipe, content, len, use_sg, NULL);
+
+		/*
+		 * If we get a stall on the bulk download, we'll retry
+		 * the bulk download -- but not the SCSI command because
+		 * in some sense the SCSI command is still 'active' and
+		 * waiting for the data. Don't ask me why this should be;
+		 * I'm only following what the Windoze driver did.
+		 *
+		 * Note that a stall for the test-and-read/write command means
+		 * that the test failed. In this case we're testing to make
+		 * sure that the device is error-free
+		 * (i.e. bit 0 -- CHK -- of status is 0). The most likely
+		 * hypothesis is that the USBAT chip somehow knows what
+		 * the device will accept, but doesn't give the device any
+		 * data until all data is received. Thus, the device would
+		 * still be waiting for the first byte of data if a stall
+		 * occurs, even if the stall implies that some data was
+		 * transferred.
+		 */
+
+		if (result == USB_STOR_XFER_SHORT ||
+				result == USB_STOR_XFER_STALLED) {
+
+			/*
+			 * If we're reading and we stalled, then clear
+			 * the bulk output pipe only the first time.
+			 */
+
+			if (direction==DMA_FROM_DEVICE && i==0) {
+				if (usb_stor_clear_halt(us,
+						us->send_bulk_pipe) < 0)
+					return USB_STOR_TRANSPORT_ERROR;
+			}
+
+			/*
+			 * Read status: is the device angry, or just busy?
+			 */
+
+ 			result = usbat_read(us, USBAT_ATA, 
+				direction==DMA_TO_DEVICE ?
+					USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS,
+				status);
+
+			if (result!=USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
+			if (*status & 0x01) // check condition
+				return USB_STOR_TRANSPORT_FAILED;
+			if (*status & 0x20) // device fault
+				return USB_STOR_TRANSPORT_FAILED;
+
+			US_DEBUGP("Redoing %s\n",
+			  direction==DMA_TO_DEVICE ? "write" : "read");
+
+		} else if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		else
+			return usbat_wait_not_busy(us, minutes);
+
+	}
+
+	US_DEBUGP("Bummer! %s bulk data 20 times failed.\n",
+		direction==DMA_TO_DEVICE ? "Writing" : "Reading");
+
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Write to multiple registers:
+ * Allows us to write specific data to any registers. The data to be written
+ * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN
+ * which gets sent through bulk out.
+ * Not designed for large transfers of data!
+ */
+static int usbat_multiple_write(struct us_data *us,
+				unsigned char *registers,
+				unsigned char *data_out,
+				unsigned short num_registers)
+{
+	int i, result;
+	unsigned char *data = us->iobuf;
+	unsigned char *command = us->iobuf;
+
+	BUG_ON(num_registers > US_IOBUF_SIZE/2);
+
+	// Write to multiple registers, ATA access
+	command[0] = 0x40;
+	command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS;
+
+	// No relevance
+	command[2] = 0;
+	command[3] = 0;
+	command[4] = 0;
+	command[5] = 0;
+
+	// Number of bytes to be transferred (incl. addresses and data)
+	command[6] = LSB_of(num_registers*2);
+	command[7] = MSB_of(num_registers*2);
+
+	// The setup command
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// Create the reg/data, reg/data sequence
+	for (i=0; i<num_registers; i++) {
+		data[i<<1] = registers[i];
+		data[1+(i<<1)] = data_out[i];
+	}
+
+	// Send the data
+	result = usbat_bulk_write(us, data, num_registers*2);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+		return usbat_wait_not_busy(us, 0);
+	else
+		return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Conditionally read blocks from device:
+ * Allows us to read blocks from a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the read will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_read_blocks(struct us_data *us,
+							 unsigned char *buffer,
+							 int len)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0xC0;
+	command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = USBAT_ATA_STATUS;
+	command[4] = 0xFD; // Timeout (ms);
+	command[5] = USBAT_QUAL_FCQ;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	// Multiple block read setup command
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+	
+	// Read the blocks we just asked for
+	result = usbat_bulk_read(us, buffer, len);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Conditionally write blocks to device:
+ * Allows us to write blocks to a specific data register, based upon the
+ * condition that a status register can be successfully masked with a status
+ * qualifier. If this condition is not initially met, the write will wait
+ * up until a maximum amount of time has elapsed, as specified by timeout.
+ * The read will start when the condition is met, otherwise the command aborts.
+ *
+ * The qualifier defined here is not the value that is masked, it defines
+ * conditions for the write to take place. The actual masked qualifier (and
+ * other related details) are defined beforehand with _set_shuttle_features().
+ */
+static int usbat_write_blocks(struct us_data *us,
+							  unsigned char *buffer,
+							  int len)
+{
+	int result;
+	unsigned char *command = us->iobuf;
+
+	command[0] = 0x40;
+	command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK;
+	command[2] = USBAT_ATA_DATA;
+	command[3] = USBAT_ATA_STATUS;
+	command[4] = 0xFD; // Timeout (ms)
+	command[5] = USBAT_QUAL_FCQ;
+	command[6] = LSB_of(len);
+	command[7] = MSB_of(len);
+
+	// Multiple block write setup command
+	result = usbat_execute_command(us, command, 8);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+	
+	// Write the data
+	result = usbat_bulk_write(us, buffer, len);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_FAILED;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Read the User IO register
+ */
+static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags)
+{
+	int result;
+
+	result = usb_stor_ctrl_transfer(us,
+		us->recv_ctrl_pipe,
+		USBAT_CMD_UIO,
+		0xC0,
+		0,
+		0,
+		data_flags,
+		USBAT_UIO_READ);
+
+	US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags));
+
+	return result;
+}
+
+/*
+ * Write to the User IO register
+ */
+static int usbat_write_user_io(struct us_data *us,
+			       unsigned char enable_flags,
+			       unsigned char data_flags)
+{
+	return usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
+		USBAT_CMD_UIO,
+		0x40,
+		short_pack(enable_flags, data_flags),
+		0,
+		NULL,
+		USBAT_UIO_WRITE);
+}
+
+/*
+ * Reset the device
+ * Often needed on media change.
+ */
+static int usbat_device_reset(struct us_data *us)
+{
+	int rc;
+
+	// Reset peripheral, enable peripheral control signals
+	// (bring reset signal up)
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+			
+	// Enable peripheral control signals
+	// (bring reset signal down)
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_OE1  | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Enable card detect
+ */
+static int usbat_device_enable_cdt(struct us_data *us)
+{
+	int rc;
+
+	// Enable peripheral control signals and card detect
+	rc = usbat_write_user_io(us,
+							 USBAT_UIO_ACKD | USBAT_UIO_OE1  | USBAT_UIO_OE0,
+							 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine if media is present.
+ */
+static int usbat_flash_check_media_present(unsigned char *uio)
+{
+	if (*uio & USBAT_UIO_UI0) {
+		US_DEBUGP("usbat_flash_check_media_present: no media detected\n");
+		return USBAT_FLASH_MEDIA_NONE;
+	}
+
+	return USBAT_FLASH_MEDIA_CF;
+}
+
+/*
+ * Determine if media has changed since last operation
+ */
+static int usbat_flash_check_media_changed(unsigned char *uio)
+{
+	if (*uio & USBAT_UIO_0) {
+		US_DEBUGP("usbat_flash_check_media_changed: media change detected\n");
+		return USBAT_FLASH_MEDIA_CHANGED;
+	}
+
+	return USBAT_FLASH_MEDIA_SAME;
+}
+
+/*
+ * Check for media change / no media and handle the situation appropriately
+ */
+static int usbat_flash_check_media(struct us_data *us,
+				   struct usbat_info *info)
+{
+	int rc;
+	unsigned char *uio = us->iobuf;
+
+	rc = usbat_read_user_io(us, uio);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// Check for media existance
+	rc = usbat_flash_check_media_present(uio);
+	if (rc == USBAT_FLASH_MEDIA_NONE) {
+		info->sense_key = 0x02;
+		info->sense_asc = 0x3A;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	// Check for media change
+	rc = usbat_flash_check_media_changed(uio);
+	if (rc == USBAT_FLASH_MEDIA_CHANGED) {
+
+		// Reset and re-enable card detect
+		rc = usbat_device_reset(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+		rc = usbat_device_enable_cdt(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		msleep(50);
+
+		rc = usbat_read_user_io(us, uio);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+		
+		info->sense_key = UNIT_ATTENTION;
+		info->sense_asc = 0x28;
+		info->sense_ascq = 0x00;
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Determine whether we are controlling a flash-based reader/writer,
+ * or a HP8200-based CD drive.
+ * Sets transport functions as appropriate.
+ */
+static int usbat_identify_device(struct us_data *us,
+				 struct usbat_info *info)
+{
+	int rc;
+	unsigned char status;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_device_reset(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	/*
+	 * By examining the device signature after a reset, we can identify
+	 * whether the device supports the ATAPI packet interface.
+	 * The flash-devices do not support this, whereas the HP CDRW's obviously
+	 * do.
+	 *
+	 * This method is not ideal, but works because no other devices have been
+	 * produced based on the USBAT/USBAT02.
+	 *
+	 * Section 9.1 of the ATAPI-4 spec states (amongst other things) that
+	 * after a device reset, a Cylinder low of 0x14 indicates that the device
+	 * does support packet commands.
+	 */
+	rc = usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, &status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("usbat_identify_device: Cylinder low is %02X\n", status);
+
+	if (status == 0x14) {
+		// Device is HP 8200
+		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
+		info->devicetype = USBAT_DEV_HP8200;
+	} else {
+		// Device is a CompactFlash reader/writer
+		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+		info->devicetype = USBAT_DEV_FLASH;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Set the transport function based on the device type
+ */
+static int usbat_set_transport(struct us_data *us,
+			       struct usbat_info *info)
+{
+	int rc;
+
+	if (!info->devicetype) {
+		rc = usbat_identify_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD) {
+			US_DEBUGP("usbat_set_transport: Could not identify device\n");
+			return 1;
+		}
+	}
+
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200)
+		us->transport = usbat_hp8200e_transport;
+	else if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+		us->transport = usbat_flash_transport;
+
+	return 0;
+}
+
+/*
+ * Read the media capacity
+ */
+static int usbat_flash_get_sector_count(struct us_data *us,
+					struct usbat_info *info)
+{
+	unsigned char registers[3] = {
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_CMD,
+	};
+	unsigned char  command[3] = { 0x01, 0xA0, 0xEC };
+	unsigned char *reply;
+	unsigned char status;
+	int rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	reply = kmalloc(512, GFP_NOIO);
+	if (!reply)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// ATAPI command : IDENTIFY DEVICE
+	rc = usbat_multiple_write(us, registers, command, 3);
+	if (rc != USB_STOR_XFER_GOOD) {
+		US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n");
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	// Read device status
+	if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) {
+		rc = USB_STOR_TRANSPORT_ERROR;
+		goto leave;
+	}
+
+	msleep(100);
+
+	// Read the device identification data
+	rc = usbat_read_block(us, reply, 512);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		goto leave;
+
+	info->sectors = ((u32)(reply[117]) << 24) |
+		((u32)(reply[116]) << 16) |
+		((u32)(reply[115]) <<  8) |
+		((u32)(reply[114])      );
+
+	rc = USB_STOR_TRANSPORT_GOOD;
+
+ leave:
+	kfree(reply);
+	return rc;
+}
+
+/*
+ * Read data from device
+ */
+static int usbat_flash_read_data(struct us_data *us,
+								 struct usbat_info *info,
+								 u32 sector,
+								 u32 sectors)
+{
+	unsigned char registers[7] = {
+		USBAT_ATA_FEATURES,
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_SECNUM,
+		USBAT_ATA_LBA_ME,
+		USBAT_ATA_LBA_HI,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_STATUS,
+	};
+	unsigned char command[7];
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	result = usbat_flash_check_media(us, info);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	// we're working in LBA mode.  according to the ATA spec,
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test
+	// since it requires > 8GB CF card.
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't read more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+ 
+		// ATAPI command 0x20 (READ SECTORS)
+		usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20);
+
+		// Write/execute ATAPI read command
+		result = usbat_multiple_write(us, registers, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		// Read the data we just requested
+		result = usbat_read_blocks(us, buffer, len);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+  	 
+		US_DEBUGP("usbat_flash_read_data:  %d bytes\n", len);
+	
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+					 &sg_idx, &sg_offset, TO_XFER_BUF);
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_GOOD;
+
+leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Write data to device
+ */
+static int usbat_flash_write_data(struct us_data *us,
+								  struct usbat_info *info,
+								  u32 sector,
+								  u32 sectors)
+{
+	unsigned char registers[7] = {
+		USBAT_ATA_FEATURES,
+		USBAT_ATA_SECCNT,
+		USBAT_ATA_SECNUM,
+		USBAT_ATA_LBA_ME,
+		USBAT_ATA_LBA_HI,
+		USBAT_ATA_DEVICE,
+		USBAT_ATA_STATUS,
+	};
+	unsigned char command[7];
+	unsigned char *buffer;
+	unsigned char  thistime;
+	unsigned int totallen, alloclen;
+	int len, result;
+	unsigned int sg_idx = 0, sg_offset = 0;
+
+	result = usbat_flash_check_media(us, info);
+	if (result != USB_STOR_TRANSPORT_GOOD)
+		return result;
+
+	// we're working in LBA mode.  according to the ATA spec,
+	// we can support up to 28-bit addressing.  I don't know if Jumpshot
+	// supports beyond 24-bit addressing.  It's kind of hard to test
+	// since it requires > 8GB CF card.
+
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	totallen = sectors * info->ssize;
+
+	// Since we don't write more than 64 KB at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	alloclen = min(totallen, 65536u);
+	buffer = kmalloc(alloclen, GFP_NOIO);
+	if (buffer == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once
+		// (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, alloclen);
+		thistime = (len / info->ssize) & 0xff;
+
+		// Get the data from the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, us->srb,
+					 &sg_idx, &sg_offset, FROM_XFER_BUF);
+
+		// ATAPI command 0x30 (WRITE SECTORS)
+		usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30);		
+
+		// Write/execute ATAPI write command
+		result = usbat_multiple_write(us, registers, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		// Write the data
+		result = usbat_write_blocks(us, buffer, len);
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			goto leave;
+
+		sector += thistime;
+		totallen -= len;
+	} while (totallen > 0);
+
+	kfree(buffer);
+	return result;
+
+leave:
+	kfree(buffer);
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/*
+ * Squeeze a potentially huge (> 65535 byte) read10 command into
+ * a little ( <= 65535 byte) ATAPI pipe
+ */
+static int usbat_hp8200e_handle_read10(struct us_data *us,
+				       unsigned char *registers,
+				       unsigned char *data,
+				       struct scsi_cmnd *srb)
+{
+	int result = USB_STOR_TRANSPORT_GOOD;
+	unsigned char *buffer;
+	unsigned int len;
+	unsigned int sector;
+	unsigned int sg_segment = 0;
+	unsigned int sg_offset = 0;
+
+	US_DEBUGP("handle_read10: transfersize %d\n",
+		srb->transfersize);
+
+	if (srb->request_bufflen < 0x10000) {
+
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+			DMA_FROM_DEVICE,
+			srb->request_buffer, 
+			srb->request_bufflen, srb->use_sg, 1);
+
+		return result;
+	}
+
+	/*
+	 * Since we're requesting more data than we can handle in
+	 * a single read command (max is 64k-1), we will perform
+	 * multiple reads, but each read must be in multiples of
+	 * a sector.  Luckily the sector size is in srb->transfersize
+	 * (see linux/drivers/scsi/sr.c).
+	 */
+
+	if (data[7+0] == GPCMD_READ_CD) {
+		len = short_pack(data[7+9], data[7+8]);
+		len <<= 16;
+		len |= data[7+7];
+		US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len);
+		srb->transfersize = srb->request_bufflen/len;
+	}
+
+	if (!srb->transfersize)  {
+		srb->transfersize = 2048; /* A guess */
+		US_DEBUGP("handle_read10: transfersize 0, forcing %d\n",
+			srb->transfersize);
+	}
+
+	// Since we only read in one block at a time, we have to create
+	// a bounce buffer and move the data a piece at a time between the
+	// bounce buffer and the actual transfer buffer.
+
+	len = (65535/srb->transfersize) * srb->transfersize;
+	US_DEBUGP("Max read is %d bytes\n", len);
+	len = min(len, srb->request_bufflen);
+	buffer = kmalloc(len, GFP_NOIO);
+	if (buffer == NULL) // bloody hell!
+		return USB_STOR_TRANSPORT_FAILED;
+	sector = short_pack(data[7+3], data[7+2]);
+	sector <<= 16;
+	sector |= short_pack(data[7+5], data[7+4]);
+	transferred = 0;
+
+	sg_segment = 0; // for keeping track of where we are in
+	sg_offset = 0;  // the scatter/gather list
+
+	while (transferred != srb->request_bufflen) {
+
+		if (len > srb->request_bufflen - transferred)
+			len = srb->request_bufflen - transferred;
+
+		data[3] = len&0xFF; 	  // (cylL) = expected length (L)
+		data[4] = (len>>8)&0xFF;  // (cylH) = expected length (H)
+
+		// Fix up the SCSI command sector and num sectors
+
+		data[7+2] = MSB_of(sector>>16); // SCSI command sector
+		data[7+3] = LSB_of(sector>>16);
+		data[7+4] = MSB_of(sector&0xFFFF);
+		data[7+5] = LSB_of(sector&0xFFFF);
+		if (data[7+0] == GPCMD_READ_CD)
+			data[7+6] = 0;
+		data[7+7] = MSB_of(len / srb->transfersize); // SCSI command
+		data[7+8] = LSB_of(len / srb->transfersize); // num sectors
+
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, 
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+			DMA_FROM_DEVICE,
+			buffer,
+			len, 0, 1);
+
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			break;
+
+		// Store the data in the transfer buffer
+		usb_stor_access_xfer_buf(buffer, len, srb,
+				 &sg_segment, &sg_offset, TO_XFER_BUF);
+
+		// Update the amount transferred and the sector number
+
+		transferred += len;
+		sector += len / srb->transfersize;
+
+	} // while transferred != srb->request_bufflen
+
+	kfree(buffer);
+	return result;
+}
+
+static int usbat_select_and_test_registers(struct us_data *us)
+{
+	int selector;
+	unsigned char *status = us->iobuf;
+	unsigned char max_selector = 0xB0;
+	if (usbat_get_device_type(us) == USBAT_DEV_FLASH)
+		max_selector = 0xA0;
+
+	// try device = master, then device = slave.
+
+	for (selector = 0xA0; selector <= max_selector; selector += 0x10) {
+
+		if (usbat_get_device_type(us) == USBAT_DEV_HP8200 &&
+			usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Initialize the USBAT processor and the storage device
+ */
+int init_usbat(struct us_data *us)
+{
+	int rc;
+	struct usbat_info *info;
+	unsigned char subcountH = USBAT_ATA_LBA_HI;
+	unsigned char subcountL = USBAT_ATA_LBA_ME;
+	unsigned char *status = us->iobuf;
+
+	us->extra = kmalloc(sizeof(struct usbat_info), GFP_NOIO);
+	if (!us->extra) {
+		US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n");
+		return 1;
+	}
+	memset(us->extra, 0, sizeof(struct usbat_info));
+	info = (struct usbat_info *) (us->extra);
+
+	// Enable peripheral control signals
+	rc = usbat_write_user_io(us,
+				 USBAT_UIO_OE1 | USBAT_UIO_OE0,
+				 USBAT_UIO_EPAD | USBAT_UIO_1);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 1\n");
+
+	msleep(2000);
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	US_DEBUGP("INIT 2\n");
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 3\n");
+
+	// At this point, we need to detect which device we are using
+	if (usbat_set_transport(us, info))
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 4\n");
+
+	if (usbat_get_device_type(us) == USBAT_DEV_HP8200) {
+		msleep(250);
+
+		// Write 0x80 to ISA port 0x3F
+		rc = usbat_write(us, USBAT_ISA, 0x3F, 0x80);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		US_DEBUGP("INIT 5\n");
+
+		// Read ISA port 0x27
+		rc = usbat_read(us, USBAT_ISA, 0x27, status);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		US_DEBUGP("INIT 6\n");
+
+		rc = usbat_read_user_io(us, status);
+		if (rc != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		US_DEBUGP("INIT 7\n");
+	}
+
+	rc = usbat_select_and_test_registers(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	US_DEBUGP("INIT 8\n");
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 9\n");
+
+	// Enable peripheral control signals and card detect
+	rc = usbat_device_enable_cdt(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	US_DEBUGP("INIT 10\n");
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 11\n");
+
+	msleep(1400);
+
+	rc = usbat_read_user_io(us, status);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 12\n");
+
+	rc = usbat_select_and_test_registers(us);
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	US_DEBUGP("INIT 13\n");
+
+	if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { 
+		subcountH = 0x02;
+		subcountL = 0x00;
+	}
+	rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1),
+									0x00, 0x88, 0x08, subcountH, subcountL);
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("INIT 14\n");
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Transport for the HP 8200e
+ */
+static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int result;
+	unsigned char *status = us->iobuf;
+	unsigned char registers[32];
+	unsigned char data[32];
+	unsigned int len;
+	int i;
+	char string[64];
+
+	len = srb->request_bufflen;
+
+	/* Send A0 (ATA PACKET COMMAND).
+	   Note: I guess we're never going to get any of the ATA
+	   commands... just ATA Packet Commands.
+ 	 */
+
+	registers[0] = USBAT_ATA_FEATURES;
+	registers[1] = USBAT_ATA_SECCNT;
+	registers[2] = USBAT_ATA_SECNUM;
+	registers[3] = USBAT_ATA_LBA_ME;
+	registers[4] = USBAT_ATA_LBA_HI;
+	registers[5] = USBAT_ATA_DEVICE;
+	registers[6] = USBAT_ATA_CMD;
+	data[0] = 0x00;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = len&0xFF; 		// (cylL) = expected length (L)
+	data[4] = (len>>8)&0xFF; 	// (cylH) = expected length (H)
+	data[5] = 0xB0; 		// (device sel) = slave
+	data[6] = 0xA0; 		// (command) = ATA PACKET COMMAND
+
+	for (i=7; i<19; i++) {
+		registers[i] = 0x10;
+		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
+	}
+
+	result = usbat_get_status(us, status);
+	US_DEBUGP("Status = %02X\n", *status);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+	if (srb->cmnd[0] == TEST_UNIT_READY)
+		transferred = 0;
+
+	if (srb->sc_data_direction == DMA_TO_DEVICE) {
+
+		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
+			registers, data, 19,
+			USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD,
+			(USBAT_QUAL_FCQ | USBAT_QUAL_ALQ),
+			DMA_TO_DEVICE,
+			srb->request_buffer, 
+			len, srb->use_sg, 10);
+
+		if (result == USB_STOR_TRANSPORT_GOOD) {
+			transferred += len;
+			US_DEBUGP("Wrote %08X bytes\n", transferred);
+		}
+
+		return result;
+
+	} else if (srb->cmnd[0] == READ_10 ||
+		   srb->cmnd[0] == GPCMD_READ_CD) {
+
+		return usbat_hp8200e_handle_read10(us, registers, data, srb);
+
+	}
+
+	if (len > 0xFFFF) {
+		US_DEBUGP("Error: len = %08X... what do I do now?\n",
+			len);
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if ( (result = usbat_multiple_write(us, 
+			registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
+		return result;
+	}
+
+	// Write the 12-byte command header.
+
+	// If the command is BLANK then set the timer for 75 minutes.
+	// Otherwise set it for 10 minutes.
+
+	// NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
+	// AT SPEED 4 IS UNRELIABLE!!!
+
+	if ( (result = usbat_write_block(us, 
+			USBAT_ATA, srb->cmnd, 12,
+			srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) !=
+				USB_STOR_TRANSPORT_GOOD) {
+		return result;
+	}
+
+	// If there is response data to be read in 
+	// then do it here.
+
+	if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) {
+
+		// How many bytes to read in? Check cylL register
+
+		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
+		    	USB_STOR_XFER_GOOD) {
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		if (len > 0xFF) { // need to read cylH also
+			len = *status;
+			if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
+				    USB_STOR_XFER_GOOD) {
+				return USB_STOR_TRANSPORT_ERROR;
+			}
+			len += ((unsigned int) *status)<<8;
+		}
+		else
+			len = *status;
+
+
+		result = usbat_read_block(us, srb->request_buffer, len);
+
+		/* Debug-print the first 32 bytes of the transfer */
+
+		if (!srb->use_sg) {
+			string[0] = 0;
+			for (i=0; i<len && i<32; i++) {
+				sprintf(string+strlen(string), "%02X ",
+				  ((unsigned char *)srb->request_buffer)[i]);
+				if ((i%16)==15) {
+					US_DEBUGP("%s\n", string);
+					string[0] = 0;
+				}
+			}
+			if (string[0]!=0)
+				US_DEBUGP("%s\n", string);
+		}
+	}
+
+	return result;
+}
+
+/*
+ * Transport for USBAT02-based CompactFlash and similar storage devices
+ */
+static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us)
+{
+	int rc;
+	struct usbat_info *info = (struct usbat_info *) (us->extra);
+	unsigned long block, blocks;
+	unsigned char *ptr = us->iobuf;
+	static unsigned char inquiry_response[36] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n");
+		memcpy(ptr, inquiry_response, sizeof(inquiry_response));
+		fill_inquiry_response(us, ptr, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		rc = usbat_flash_check_media(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		rc = usbat_flash_get_sector_count(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+		US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
+			  info->sectors, info->ssize);
+
+		// build the reply
+		// note: must return the sector number of the last sector,
+		// *not* the total number of sectors
+		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
+		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
+		usb_stor_set_xfer_buf(ptr, 8, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		US_DEBUGP("usbat_flash_transport:  Gah! MODE_SELECT_10.\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+				((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("usbat_flash_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// I don't think we'll ever see a READ_12 but support it anyway...
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_read_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_write_data(us, info, block, blocks);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// I don't think we'll ever see a WRITE_12 but support it anyway...
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx  count %ld\n", block, blocks);
+		return usbat_flash_write_data(us, info, block, blocks);
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n");
+
+		rc = usbat_flash_check_media(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		return usbat_check_status(us);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n");
+
+		memset(ptr, 0, 18);
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+		usb_stor_set_xfer_buf(ptr, 18, srb);
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		// sure.  whatever.  not like we can stop the user from popping
+		// the media out of the device (no locking doors, etc)
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n",
+			  srb->cmnd[0], srb->cmnd[0]);
+	info->sense_key = 0x05;
+	info->sense_asc = 0x20;
+	info->sense_ascq = 0x00;
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Default transport function. Attempts to detect which transport function
+ * should be called, makes it the new default, and calls it.
+ *
+ * This function should never be called. Our usbat_init() function detects the
+ * device type and changes the us->transport ptr to the transport function
+ * relevant to the device.
+ * However, we'll support this impossible(?) case anyway.
+ */
+int usbat_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct usbat_info *info = (struct usbat_info*) (us->extra);
+
+	if (usbat_set_transport(us, info))
+		return USB_STOR_TRANSPORT_ERROR;
+
+	return us->transport(srb, us);	
+}
+
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
new file mode 100644
index 0000000..5b8e867
--- /dev/null
+++ b/drivers/usb/storage/shuttle_usbat.h
@@ -0,0 +1,123 @@
+/* Driver for SCM Microsystems USB-ATAPI cable
+ * Header File
+ *
+ * $Id: shuttle_usbat.h,v 1.5 2000/09/17 14:44:52 groovyjava Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Robert Baruch (autophile@dol.net)
+ *   (c) 2004, 2005 Daniel Drake <dsd@gentoo.org>
+ *
+ * See shuttle_usbat.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_SHUTTLE_USBAT_H
+#define _USB_SHUTTLE_USBAT_H
+
+/* Supported device types */
+#define USBAT_DEV_HP8200	0x01
+#define USBAT_DEV_FLASH		0x02
+
+#define USBAT_EPP_PORT		0x10
+#define USBAT_EPP_REGISTER	0x30
+#define USBAT_ATA		0x40
+#define USBAT_ISA		0x50
+
+/* Commands (need to be logically OR'd with an access type */
+#define USBAT_CMD_READ_REG		0x00
+#define USBAT_CMD_WRITE_REG		0x01
+#define USBAT_CMD_READ_BLOCK	0x02
+#define USBAT_CMD_WRITE_BLOCK	0x03
+#define USBAT_CMD_COND_READ_BLOCK	0x04
+#define USBAT_CMD_COND_WRITE_BLOCK	0x05
+#define USBAT_CMD_WRITE_REGS	0x07
+
+/* Commands (these don't need an access type) */
+#define USBAT_CMD_EXEC_CMD	0x80
+#define USBAT_CMD_SET_FEAT	0x81
+#define USBAT_CMD_UIO		0x82
+
+/* Methods of accessing UIO register */
+#define USBAT_UIO_READ	1
+#define USBAT_UIO_WRITE	0
+
+/* Qualifier bits */
+#define USBAT_QUAL_FCQ	0x20 // full compare
+#define USBAT_QUAL_ALQ	0x10 // auto load subcount
+
+/* USBAT Flash Media status types */
+#define USBAT_FLASH_MEDIA_NONE	0
+#define USBAT_FLASH_MEDIA_CF	1
+
+/* USBAT Flash Media change types */
+#define USBAT_FLASH_MEDIA_SAME	0
+#define USBAT_FLASH_MEDIA_CHANGED	1
+
+/* USBAT ATA registers */
+#define USBAT_ATA_DATA      0x10  // read/write data (R/W)
+#define USBAT_ATA_FEATURES  0x11  // set features (W)
+#define USBAT_ATA_ERROR     0x11  // error (R)
+#define USBAT_ATA_SECCNT    0x12  // sector count (R/W)
+#define USBAT_ATA_SECNUM    0x13  // sector number (R/W)
+#define USBAT_ATA_LBA_ME    0x14  // cylinder low (R/W)
+#define USBAT_ATA_LBA_HI    0x15  // cylinder high (R/W)
+#define USBAT_ATA_DEVICE    0x16  // head/device selection (R/W)
+#define USBAT_ATA_STATUS    0x17  // device status (R)
+#define USBAT_ATA_CMD       0x17  // device command (W)
+#define USBAT_ATA_ALTSTATUS 0x0E  // status (no clear IRQ) (R)
+
+/* USBAT User I/O Data registers */
+#define USBAT_UIO_EPAD		0x80 // Enable Peripheral Control Signals
+#define USBAT_UIO_CDT		0x40 // Card Detect (Read Only)
+				     // CDT = ACKD & !UI1 & !UI0
+#define USBAT_UIO_1		0x20 // I/O 1
+#define USBAT_UIO_0		0x10 // I/O 0
+#define USBAT_UIO_EPP_ATA	0x08 // 1=EPP mode, 0=ATA mode
+#define USBAT_UIO_UI1		0x04 // Input 1
+#define USBAT_UIO_UI0		0x02 // Input 0
+#define USBAT_UIO_INTR_ACK	0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP)
+
+/* USBAT User I/O Enable registers */
+#define USBAT_UIO_DRVRST	0x80 // Reset Peripheral
+#define USBAT_UIO_ACKD		0x40 // Enable Card Detect
+#define USBAT_UIO_OE1		0x20 // I/O 1 set=output/clr=input
+				     // If ACKD=1, set OE1 to 1 also.
+#define USBAT_UIO_OE0		0x10 // I/O 0 set=output/clr=input
+#define USBAT_UIO_ADPRST	0x01 // Reset SCM chip
+
+/* USBAT Features */
+#define USBAT_FEAT_ETEN	0x80 // External trigger enable
+#define USBAT_FEAT_U1	0x08
+#define USBAT_FEAT_U0	0x04
+#define USBAT_FEAT_ET1	0x02
+#define USBAT_FEAT_ET2	0x01
+
+extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int init_usbat(struct us_data *us);
+
+struct usbat_info {
+	int devicetype;
+
+	/* Used for Flash readers only */
+	unsigned long sectors;     // total sector count
+	unsigned long ssize;       // sector size in bytes
+
+	unsigned char sense_key;
+	unsigned long sense_asc;   // additional sense code
+	unsigned long sense_ascq;  // additional sense code qualifier
+};
+
+#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
new file mode 100644
index 0000000..d2c3d2f
--- /dev/null
+++ b/drivers/usb/storage/transport.c
@@ -0,0 +1,1215 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * $Id: transport.c,v 1.47 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov)
+ *   (c) 2002 Alan Stern <stern@rowland.org>
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "protocol.h"
+#include "scsiglue.h"
+#include "debug.h"
+
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+/*
+ * This is subtle, so pay attention:
+ * ---------------------------------
+ * We're very concerned about races with a command abort.  Hanging this code
+ * is a sure fire way to hang the kernel.  (Note that this discussion applies
+ * only to transactions resulting from a scsi queued-command, since only
+ * these transactions are subject to a scsi abort.  Other transactions, such
+ * as those occurring during device-specific initialization, must be handled
+ * by a separate code path.)
+ *
+ * The abort function (usb_storage_command_abort() in scsiglue.c) first
+ * sets the machine state and the ABORTING bit in us->flags to prevent
+ * new URBs from being submitted.  It then calls usb_stor_stop_transport()
+ * below, which atomically tests-and-clears the URB_ACTIVE bit in us->flags
+ * to see if the current_urb needs to be stopped.  Likewise, the SG_ACTIVE
+ * bit is tested to see if the current_sg scatter-gather request needs to be
+ * stopped.  The timeout callback routine does much the same thing.
+ *
+ * When a disconnect occurs, the DISCONNECTING bit in us->flags is set to
+ * prevent new URBs from being submitted, and usb_stor_stop_transport() is
+ * called to stop any ongoing requests.
+ *
+ * The submit function first verifies that the submitting is allowed
+ * (neither ABORTING nor DISCONNECTING bits are set) and that the submit
+ * completes without errors, and only then sets the URB_ACTIVE bit.  This
+ * prevents the stop_transport() function from trying to cancel the URB
+ * while the submit call is underway.  Next, the submit function must test
+ * the flags to see if an abort or disconnect occurred during the submission
+ * or before the URB_ACTIVE bit was set.  If so, it's essential to cancel
+ * the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit
+ * is still set).  Either way, the function must then wait for the URB to
+ * finish.  Note that because the URB_ASYNC_UNLINK flag is set, the URB can
+ * still be in progress even after a call to usb_unlink_urb() returns.
+ *
+ * The idea is that (1) once the ABORTING or DISCONNECTING bit is set,
+ * either the stop_transport() function or the submitting function
+ * is guaranteed to call usb_unlink_urb() for an active URB,
+ * and (2) test_and_clear_bit() prevents usb_unlink_urb() from being
+ * called more than once or from being called during usb_submit_urb().
+ */
+
+/* This is the completion handler which will wake us up when an URB
+ * completes.
+ */
+static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs)
+{
+	struct completion *urb_done_ptr = (struct completion *)urb->context;
+
+	complete(urb_done_ptr);
+}
+ 
+/* This is the timeout handler which will cancel an URB when its timeout
+ * expires.
+ */
+static void timeout_handler(unsigned long us_)
+{
+	struct us_data *us = (struct us_data *) us_;
+
+	if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
+		US_DEBUGP("Timeout -- cancelling URB\n");
+		usb_unlink_urb(us->current_urb);
+	}
+}
+
+/* This is the common part of the URB message submission code
+ *
+ * All URBs from the usb-storage driver involved in handling a queued scsi
+ * command _must_ pass through this function (or something like it) for the
+ * abort mechanisms to work properly.
+ */
+static int usb_stor_msg_common(struct us_data *us, int timeout)
+{
+	struct completion urb_done;
+	struct timer_list to_timer;
+	int status;
+
+	/* don't submit URBs during abort/disconnect processing */
+	if (us->flags & ABORTING_OR_DISCONNECTING)
+		return -EIO;
+
+	/* set up data structures for the wakeup system */
+	init_completion(&urb_done);
+
+	/* fill the common fields in the URB */
+	us->current_urb->context = &urb_done;
+	us->current_urb->actual_length = 0;
+	us->current_urb->error_count = 0;
+	us->current_urb->status = 0;
+
+	/* we assume that if transfer_buffer isn't us->iobuf then it
+	 * hasn't been mapped for DMA.  Yes, this is clunky, but it's
+	 * easier than always having the caller tell us whether the
+	 * transfer buffer has already been mapped. */
+	us->current_urb->transfer_flags =
+			URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP;
+	if (us->current_urb->transfer_buffer == us->iobuf)
+		us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+	us->current_urb->transfer_dma = us->iobuf_dma;
+	us->current_urb->setup_dma = us->cr_dma;
+
+	/* submit the URB */
+	status = usb_submit_urb(us->current_urb, GFP_NOIO);
+	if (status) {
+		/* something went wrong */
+		return status;
+	}
+
+	/* since the URB has been submitted successfully, it's now okay
+	 * to cancel it */
+	set_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+
+	/* did an abort/disconnect occur during the submission? */
+	if (us->flags & ABORTING_OR_DISCONNECTING) {
+
+		/* cancel the URB, if it hasn't been cancelled already */
+		if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
+			US_DEBUGP("-- cancelling URB\n");
+			usb_unlink_urb(us->current_urb);
+		}
+	}
+ 
+	/* submit the timeout timer, if a timeout was requested */
+	if (timeout > 0) {
+		init_timer(&to_timer);
+		to_timer.expires = jiffies + timeout;
+		to_timer.function = timeout_handler;
+		to_timer.data = (unsigned long) us;
+		add_timer(&to_timer);
+	}
+
+	/* wait for the completion of the URB */
+	wait_for_completion(&urb_done);
+	clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
+ 
+	/* clean up the timeout timer */
+	if (timeout > 0)
+		del_timer_sync(&to_timer);
+
+	/* return the URB status */
+	return us->current_urb->status;
+}
+
+/*
+ * Transfer one control message, with timeouts, and allowing early
+ * termination.  Return codes are usual -Exxx, *not* USB_STOR_XFER_xxx.
+ */
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+		 u8 request, u8 requesttype, u16 value, u16 index, 
+		 void *data, u16 size, int timeout)
+{
+	int status;
+
+	US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+			__FUNCTION__, request, requesttype,
+			value, index, size);
+
+	/* fill in the devrequest structure */
+	us->cr->bRequestType = requesttype;
+	us->cr->bRequest = request;
+	us->cr->wValue = cpu_to_le16(value);
+	us->cr->wIndex = cpu_to_le16(index);
+	us->cr->wLength = cpu_to_le16(size);
+
+	/* fill and submit the URB */
+	usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, 
+			 (unsigned char*) us->cr, data, size, 
+			 usb_stor_blocking_completion, NULL);
+	status = usb_stor_msg_common(us, timeout);
+
+	/* return the actual length of the data transferred if no error */
+	if (status == 0)
+		status = us->current_urb->actual_length;
+	return status;
+}
+
+/* This is a version of usb_clear_halt() that allows early termination and
+ * doesn't read the status from the device -- this is because some devices
+ * crash their internal firmware when the status is requested after a halt.
+ *
+ * A definitive list of these 'bad' devices is too difficult to maintain or
+ * make complete enough to be useful.  This problem was first observed on the
+ * Hagiwara FlashGate DUAL unit.  However, bus traces reveal that neither
+ * MacOS nor Windows checks the status after clearing a halt.
+ *
+ * Since many vendors in this space limit their testing to interoperability
+ * with these two OSes, specification violations like this one are common.
+ */
+int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
+{
+	int result;
+	int endp = usb_pipeendpoint(pipe);
+
+	if (usb_pipein (pipe))
+		endp |= USB_DIR_IN;
+
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
+		USB_ENDPOINT_HALT, endp,
+		NULL, 0, 3*HZ);
+
+	/* reset the endpoint toggle */
+	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+		usb_pipeout(pipe), 0);
+
+	US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
+	return result;
+}
+
+
+/*
+ * Interpret the results of a URB transfer
+ *
+ * This function prints appropriate debugging messages, clears halts on
+ * non-control endpoints, and translates the status to the corresponding
+ * USB_STOR_XFER_xxx return code.
+ */
+static int interpret_urb_result(struct us_data *us, unsigned int pipe,
+		unsigned int length, int result, unsigned int partial)
+{
+	US_DEBUGP("Status code %d; transferred %u/%u\n",
+			result, partial, length);
+	switch (result) {
+
+	/* no error code; did we send all the data? */
+	case 0:
+		if (partial != length) {
+			US_DEBUGP("-- short transfer\n");
+			return USB_STOR_XFER_SHORT;
+		}
+
+		US_DEBUGP("-- transfer complete\n");
+		return USB_STOR_XFER_GOOD;
+
+	/* stalled */
+	case -EPIPE:
+		/* for control endpoints, (used by CB[I]) a stall indicates
+		 * a failed command */
+		if (usb_pipecontrol(pipe)) {
+			US_DEBUGP("-- stall on control pipe\n");
+			return USB_STOR_XFER_STALLED;
+		}
+
+		/* for other sorts of endpoint, clear the stall */
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		if (usb_stor_clear_halt(us, pipe) < 0)
+			return USB_STOR_XFER_ERROR;
+		return USB_STOR_XFER_STALLED;
+
+	/* timeout or excessively long NAK */
+	case -ETIMEDOUT:
+		US_DEBUGP("-- timeout or NAK\n");
+		return USB_STOR_XFER_ERROR;
+
+	/* babble - the device tried to send more than we wanted to read */
+	case -EOVERFLOW:
+		US_DEBUGP("-- babble\n");
+		return USB_STOR_XFER_LONG;
+
+	/* the transfer was cancelled by abort, disconnect, or timeout */
+	case -ECONNRESET:
+		US_DEBUGP("-- transfer cancelled\n");
+		return USB_STOR_XFER_ERROR;
+
+	/* short scatter-gather read transfer */
+	case -EREMOTEIO:
+		US_DEBUGP("-- short read transfer\n");
+		return USB_STOR_XFER_SHORT;
+
+	/* abort or disconnect in progress */
+	case -EIO:
+		US_DEBUGP("-- abort or disconnect in progress\n");
+		return USB_STOR_XFER_ERROR;
+
+	/* the catch-all error case */
+	default:
+		US_DEBUGP("-- unknown error\n");
+		return USB_STOR_XFER_ERROR;
+	}
+}
+
+/*
+ * Transfer one control message, without timeouts, but allowing early
+ * termination.  Return codes are USB_STOR_XFER_xxx.
+ */
+int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size)
+{
+	int result;
+
+	US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
+			__FUNCTION__, request, requesttype,
+			value, index, size);
+
+	/* fill in the devrequest structure */
+	us->cr->bRequestType = requesttype;
+	us->cr->bRequest = request;
+	us->cr->wValue = cpu_to_le16(value);
+	us->cr->wIndex = cpu_to_le16(index);
+	us->cr->wLength = cpu_to_le16(size);
+
+	/* fill and submit the URB */
+	usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, 
+			 (unsigned char*) us->cr, data, size, 
+			 usb_stor_blocking_completion, NULL);
+	result = usb_stor_msg_common(us, 0);
+
+	return interpret_urb_result(us, pipe, size, result,
+			us->current_urb->actual_length);
+}
+
+/*
+ * Receive one interrupt buffer, without timeouts, but allowing early
+ * termination.  Return codes are USB_STOR_XFER_xxx.
+ *
+ * This routine always uses us->recv_intr_pipe as the pipe and
+ * us->ep_bInterval as the interrupt interval.
+ */
+static int usb_stor_intr_transfer(struct us_data *us, void *buf,
+				  unsigned int length)
+{
+	int result;
+	unsigned int pipe = us->recv_intr_pipe;
+	unsigned int maxp;
+
+	US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
+
+	/* calculate the max packet size */
+	maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
+	if (maxp > length)
+		maxp = length;
+
+	/* fill and submit the URB */
+	usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, buf,
+			maxp, usb_stor_blocking_completion, NULL,
+			us->ep_bInterval);
+	result = usb_stor_msg_common(us, 0);
+
+	return interpret_urb_result(us, pipe, length, result,
+			us->current_urb->actual_length);
+}
+
+/*
+ * Transfer one buffer via bulk pipe, without timeouts, but allowing early
+ * termination.  Return codes are USB_STOR_XFER_xxx.  If the bulk pipe
+ * stalls during the transfer, the halt is automatically cleared.
+ */
+int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+	void *buf, unsigned int length, unsigned int *act_len)
+{
+	int result;
+
+	US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
+
+	/* fill and submit the URB */
+	usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
+		      usb_stor_blocking_completion, NULL);
+	result = usb_stor_msg_common(us, 0);
+
+	/* store the actual length of the data transferred */
+	if (act_len)
+		*act_len = us->current_urb->actual_length;
+	return interpret_urb_result(us, pipe, length, result, 
+			us->current_urb->actual_length);
+}
+
+/*
+ * Transfer a scatter-gather list via bulk transfer
+ *
+ * This function does basically the same thing as usb_stor_bulk_transfer_buf()
+ * above, but it uses the usbcore scatter-gather library.
+ */
+static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
+		struct scatterlist *sg, int num_sg, unsigned int length,
+		unsigned int *act_len)
+{
+	int result;
+
+	/* don't submit s-g requests during abort/disconnect processing */
+	if (us->flags & ABORTING_OR_DISCONNECTING)
+		return USB_STOR_XFER_ERROR;
+
+	/* initialize the scatter-gather request block */
+	US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__,
+			length, num_sg);
+	result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
+			sg, num_sg, length, SLAB_NOIO);
+	if (result) {
+		US_DEBUGP("usb_sg_init returned %d\n", result);
+		return USB_STOR_XFER_ERROR;
+	}
+
+	/* since the block has been initialized successfully, it's now
+	 * okay to cancel it */
+	set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
+
+	/* did an abort/disconnect occur during the submission? */
+	if (us->flags & ABORTING_OR_DISCONNECTING) {
+
+		/* cancel the request, if it hasn't been cancelled already */
+		if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
+			US_DEBUGP("-- cancelling sg request\n");
+			usb_sg_cancel(&us->current_sg);
+		}
+	}
+
+	/* wait for the completion of the transfer */
+	usb_sg_wait(&us->current_sg);
+	clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
+
+	result = us->current_sg.status;
+	if (act_len)
+		*act_len = us->current_sg.bytes;
+	return interpret_urb_result(us, pipe, length, result,
+			us->current_sg.bytes);
+}
+
+/*
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses usb_stor_bulk_transfer_buf() and
+ * usb_stor_bulk_transfer_sglist() to achieve its goals --
+ * this function simply determines whether we're going to use
+ * scatter-gather or not, and acts appropriately.
+ */
+int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
+		void *buf, unsigned int length_left, int use_sg, int *residual)
+{
+	int result;
+	unsigned int partial;
+
+	/* are we scatter-gathering? */
+	if (use_sg) {
+		/* use the usb core scatter-gather primitives */
+		result = usb_stor_bulk_transfer_sglist(us, pipe,
+				(struct scatterlist *) buf, use_sg,
+				length_left, &partial);
+		length_left -= partial;
+	} else {
+		/* no scatter-gather, just make the request */
+		result = usb_stor_bulk_transfer_buf(us, pipe, buf, 
+				length_left, &partial);
+		length_left -= partial;
+	}
+
+	/* store the residual and return the error code */
+	if (residual)
+		*residual = length_left;
+	return result;
+}
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+/* Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and receive the response.
+ */
+void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	int need_auto_sense;
+	int result;
+
+	/* send the command to the transport layer */
+	srb->resid = 0;
+	result = us->transport(srb, us);
+
+	/* if the command gets aborted by the higher layers, we need to
+	 * short-circuit all other processing
+	 */
+	if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+		US_DEBUGP("-- command was aborted\n");
+		goto Handle_Abort;
+	}
+
+	/* if there is a transport error, reset and don't auto-sense */
+	if (result == USB_STOR_TRANSPORT_ERROR) {
+		US_DEBUGP("-- transport indicates error, resetting\n");
+		us->transport_reset(us);
+		srb->result = DID_ERROR << 16;
+		return;
+	}
+
+	/* if the transport provided its own sense data, don't auto-sense */
+	if (result == USB_STOR_TRANSPORT_NO_SENSE) {
+		srb->result = SAM_STAT_CHECK_CONDITION;
+		return;
+	}
+
+	srb->result = SAM_STAT_GOOD;
+
+	/* Determine if we need to auto-sense
+	 *
+	 * I normally don't use a flag like this, but it's almost impossible
+	 * to understand what's going on here if I don't.
+	 */
+	need_auto_sense = 0;
+
+	/*
+	 * If we're running the CB transport, which is incapable
+	 * of determining status on its own, we will auto-sense
+	 * unless the operation involved a data-in transfer.  Devices
+	 * can signal most data-in errors by stalling the bulk-in pipe.
+	 */
+	if ((us->protocol == US_PR_CB || us->protocol == US_PR_DPCM_USB) &&
+			srb->sc_data_direction != DMA_FROM_DEVICE) {
+		US_DEBUGP("-- CB transport device requiring auto-sense\n");
+		need_auto_sense = 1;
+	}
+
+	/*
+	 * If we have a failure, we're going to do a REQUEST_SENSE 
+	 * automatically.  Note that we differentiate between a command
+	 * "failure" and an "error" in the transport mechanism.
+	 */
+	if (result == USB_STOR_TRANSPORT_FAILED) {
+		US_DEBUGP("-- transport indicates command failure\n");
+		need_auto_sense = 1;
+	}
+
+	/*
+	 * A short transfer on a command where we don't expect it
+	 * is unusual, but it doesn't mean we need to auto-sense.
+	 */
+	if ((srb->resid > 0) &&
+	    !((srb->cmnd[0] == REQUEST_SENSE) ||
+	      (srb->cmnd[0] == INQUIRY) ||
+	      (srb->cmnd[0] == MODE_SENSE) ||
+	      (srb->cmnd[0] == LOG_SENSE) ||
+	      (srb->cmnd[0] == MODE_SENSE_10))) {
+		US_DEBUGP("-- unexpectedly short transfer\n");
+	}
+
+	/* Now, if we need to do the auto-sense, let's do it */
+	if (need_auto_sense) {
+		int temp_result;
+		void* old_request_buffer;
+		unsigned short old_sg;
+		unsigned old_request_bufflen;
+		unsigned char old_sc_data_direction;
+		unsigned char old_cmd_len;
+		unsigned char old_cmnd[MAX_COMMAND_SIZE];
+		unsigned long old_serial_number;
+		int old_resid;
+
+		US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
+
+		/* save the old command */
+		memcpy(old_cmnd, srb->cmnd, MAX_COMMAND_SIZE);
+		old_cmd_len = srb->cmd_len;
+
+		/* set the command and the LUN */
+		memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
+		srb->cmnd[0] = REQUEST_SENSE;
+		srb->cmnd[1] = old_cmnd[1] & 0xE0;
+		srb->cmnd[4] = 18;
+
+		/* FIXME: we must do the protocol translation here */
+		if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI)
+			srb->cmd_len = 6;
+		else
+			srb->cmd_len = 12;
+
+		/* set the transfer direction */
+		old_sc_data_direction = srb->sc_data_direction;
+		srb->sc_data_direction = DMA_FROM_DEVICE;
+
+		/* use the new buffer we have */
+		old_request_buffer = srb->request_buffer;
+		srb->request_buffer = srb->sense_buffer;
+
+		/* set the buffer length for transfer */
+		old_request_bufflen = srb->request_bufflen;
+		srb->request_bufflen = 18;
+
+		/* set up for no scatter-gather use */
+		old_sg = srb->use_sg;
+		srb->use_sg = 0;
+
+		/* change the serial number -- toggle the high bit*/
+		old_serial_number = srb->serial_number;
+		srb->serial_number ^= 0x80000000;
+
+		/* issue the auto-sense command */
+		old_resid = srb->resid;
+		srb->resid = 0;
+		temp_result = us->transport(us->srb, us);
+
+		/* let's clean up right away */
+		srb->resid = old_resid;
+		srb->request_buffer = old_request_buffer;
+		srb->request_bufflen = old_request_bufflen;
+		srb->use_sg = old_sg;
+		srb->serial_number = old_serial_number;
+		srb->sc_data_direction = old_sc_data_direction;
+		srb->cmd_len = old_cmd_len;
+		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
+
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+			US_DEBUGP("-- auto-sense aborted\n");
+			goto Handle_Abort;
+		}
+		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+			US_DEBUGP("-- auto-sense failure\n");
+
+			/* we skip the reset if this happens to be a
+			 * multi-target device, since failure of an
+			 * auto-sense is perfectly valid
+			 */
+			if (!(us->flags & US_FL_SCM_MULT_TARG))
+				us->transport_reset(us);
+			srb->result = DID_ERROR << 16;
+			return;
+		}
+
+		US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
+		US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
+			  srb->sense_buffer[0],
+			  srb->sense_buffer[2] & 0xf,
+			  srb->sense_buffer[12], 
+			  srb->sense_buffer[13]);
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		usb_stor_show_sense(
+			  srb->sense_buffer[2] & 0xf,
+			  srb->sense_buffer[12], 
+			  srb->sense_buffer[13]);
+#endif
+
+		/* set the result so the higher layers expect this data */
+		srb->result = SAM_STAT_CHECK_CONDITION;
+
+		/* If things are really okay, then let's show that.  Zero
+		 * out the sense buffer so the higher layers won't realize
+		 * we did an unsolicited auto-sense. */
+		if (result == USB_STOR_TRANSPORT_GOOD &&
+			/* Filemark 0, ignore EOM, ILI 0, no sense */
+				(srb->sense_buffer[2] & 0xaf) == 0 &&
+			/* No ASC or ASCQ */
+				srb->sense_buffer[12] == 0 &&
+				srb->sense_buffer[13] == 0) {
+			srb->result = SAM_STAT_GOOD;
+			srb->sense_buffer[0] = 0x0;
+		}
+	}
+
+	/* Did we transfer less than the minimum amount required? */
+	if (srb->result == SAM_STAT_GOOD &&
+			srb->request_bufflen - srb->resid < srb->underflow)
+		srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
+
+	return;
+
+	/* abort processing: the bulk-only transport requires a reset
+	 * following an abort */
+  Handle_Abort:
+	srb->result = DID_ABORT << 16;
+	if (us->protocol == US_PR_BULK)
+		us->transport_reset(us);
+}
+
+/* Stop the current URB transfer */
+void usb_stor_stop_transport(struct us_data *us)
+{
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	/* If the state machine is blocked waiting for an URB,
+	 * let's wake it up.  The test_and_clear_bit() call
+	 * guarantees that if a URB has just been submitted,
+	 * it won't be cancelled more than once. */
+	if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
+		US_DEBUGP("-- cancelling URB\n");
+		usb_unlink_urb(us->current_urb);
+	}
+
+	/* If we are waiting for a scatter-gather operation, cancel it. */
+	if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
+		US_DEBUGP("-- cancelling sg request\n");
+		usb_sg_cancel(&us->current_sg);
+	}
+}
+
+/*
+ * Control/Bulk/Interrupt transport
+ */
+
+int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned int transfer_length = srb->request_bufflen;
+	unsigned int pipe = 0;
+	int result;
+
+	/* COMMAND STAGE */
+	/* let's send the command via the control pipe */
+	result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+				      US_CBI_ADSC, 
+				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
+				      us->ifnum, srb->cmnd, srb->cmd_len);
+
+	/* check the return code for the command */
+	US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
+
+	/* if we stalled the command, it means command failed */
+	if (result == USB_STOR_XFER_STALLED) {
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* Uh oh... serious problem here */
+	if (result != USB_STOR_XFER_GOOD) {
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* DATA STAGE */
+	/* transfer the data payload for this command, if one exists*/
+	if (transfer_length) {
+		pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer, transfer_length,
+					srb->use_sg, &srb->resid);
+		US_DEBUGP("CBI data stage result is 0x%x\n", result);
+
+		/* if we stalled the data transfer it means command failed */
+		if (result == USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_FAILED;
+		if (result > USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* STATUS STAGE */
+	result = usb_stor_intr_transfer(us, us->iobuf, 2);
+	US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", 
+			us->iobuf[0], us->iobuf[1]);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* UFI gives us ASC and ASCQ, like a request sense
+	 *
+	 * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI
+	 * devices, so we ignore the information for those commands.  Note
+	 * that this means we could be ignoring a real error on these
+	 * commands, but that can't be helped.
+	 */
+	if (us->subclass == US_SC_UFI) {
+		if (srb->cmnd[0] == REQUEST_SENSE ||
+		    srb->cmnd[0] == INQUIRY)
+			return USB_STOR_TRANSPORT_GOOD;
+		if (us->iobuf[0])
+			goto Failed;
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	/* If not UFI, we interpret the data as a result code 
+	 * The first byte should always be a 0x0.
+	 *
+	 * Some bogus devices don't follow that rule.  They stuff the ASC
+	 * into the first byte -- so if it's non-zero, call it a failure.
+	 */
+	if (us->iobuf[0]) {
+		US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n",
+				us->iobuf[0]);
+		goto Failed;
+
+	}
+
+	/* The second byte & 0x0F should be 0x0 for good, otherwise error */
+	switch (us->iobuf[1] & 0x0F) {
+		case 0x00: 
+			return USB_STOR_TRANSPORT_GOOD;
+		case 0x01: 
+			goto Failed;
+	}
+	return USB_STOR_TRANSPORT_ERROR;
+
+	/* the CBI spec requires that the bulk pipe must be cleared
+	 * following any data-in/out command failure (section 2.4.3.1.3)
+	 */
+  Failed:
+	if (pipe)
+		usb_stor_clear_halt(us, pipe);
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Control/Bulk transport
+ */
+int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	unsigned int transfer_length = srb->request_bufflen;
+	int result;
+
+	/* COMMAND STAGE */
+	/* let's send the command via the control pipe */
+	result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
+				      US_CBI_ADSC, 
+				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
+				      us->ifnum, srb->cmnd, srb->cmd_len);
+
+	/* check the return code for the command */
+	US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
+
+	/* if we stalled the command, it means command failed */
+	if (result == USB_STOR_XFER_STALLED) {
+		return USB_STOR_TRANSPORT_FAILED;
+	}
+
+	/* Uh oh... serious problem here */
+	if (result != USB_STOR_XFER_GOOD) {
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* DATA STAGE */
+	/* transfer the data payload for this command, if one exists*/
+	if (transfer_length) {
+		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer, transfer_length,
+					srb->use_sg, &srb->resid);
+		US_DEBUGP("CB data stage result is 0x%x\n", result);
+
+		/* if we stalled the data transfer it means command failed */
+		if (result == USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_FAILED;
+		if (result > USB_STOR_XFER_STALLED)
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* STATUS STAGE */
+	/* NOTE: CB does not have a status stage.  Silly, I know.  So
+	 * we have to catch this at a higher level.
+	 */
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * Bulk only transport
+ */
+
+/* Determine what the maximum LUN supported is */
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+	int result;
+
+	/* issue the command */
+	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+				 US_BULK_GET_MAX_LUN, 
+				 USB_DIR_IN | USB_TYPE_CLASS | 
+				 USB_RECIP_INTERFACE,
+				 0, us->ifnum, us->iobuf, 1, HZ);
+
+	US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", 
+		  result, us->iobuf[0]);
+
+	/* if we have a successful request, return the result */
+	if (result > 0)
+		return us->iobuf[0];
+
+	/* 
+	 * Some devices (i.e. Iomega Zip100) need this -- apparently
+	 * the bulk pipes get STALLed when the GetMaxLUN request is
+	 * processed.   This is, in theory, harmless to all other devices
+	 * (regardless of if they stall or not).
+	 */
+	if (result == -EPIPE) {
+		usb_stor_clear_halt(us, us->recv_bulk_pipe);
+		usb_stor_clear_halt(us, us->send_bulk_pipe);
+	}
+
+	/*
+	 * Some devices don't like GetMaxLUN.  They may STALL the control
+	 * pipe, they may return a zero-length result, they may do nothing at
+	 * all and timeout, or they may fail in even more bizarrely creative
+	 * ways.  In these cases the best approach is to use the default
+	 * value: only one LUN.
+	 */
+	return 0;
+}
+
+int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+	unsigned int transfer_length = srb->request_bufflen;
+	unsigned int residue;
+	int result;
+	int fake_sense = 0;
+	unsigned int cswlen;
+	unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+	/* Take care of BULK32 devices; set extra byte to 0 */
+	if ( unlikely(us->flags & US_FL_BULK32)) {
+		cbwlen = 32;
+		us->iobuf[31] = 0;
+	}
+
+	/* set up the command wrapper */
+	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+	bcb->DataTransferLength = cpu_to_le32(transfer_length);
+	bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+	bcb->Tag = srb->serial_number;
+	bcb->Lun = srb->device->lun;
+	if (us->flags & US_FL_SCM_MULT_TARG)
+		bcb->Lun |= srb->device->id << 4;
+	bcb->Length = srb->cmd_len;
+
+	/* copy the command payload */
+	memset(bcb->CDB, 0, sizeof(bcb->CDB));
+	memcpy(bcb->CDB, srb->cmnd, bcb->Length);
+
+	/* send it to out endpoint */
+	US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+			le32_to_cpu(bcb->Signature), bcb->Tag,
+			le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
+			(bcb->Lun >> 4), (bcb->Lun & 0x0F), 
+			bcb->Length);
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+				bcb, cbwlen, NULL);
+	US_DEBUGP("Bulk command transfer result=%d\n", result);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* DATA STAGE */
+	/* send/receive data payload, if there is any */
+
+	/* Some USB-IDE converter chips need a 100us delay between the
+	 * command phase and the data phase.  Some devices need a little
+	 * more than that, probably because of clock rate inaccuracies. */
+	if (unlikely(us->flags & US_FL_GO_SLOW))
+		udelay(110);
+
+	if (transfer_length) {
+		unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer, transfer_length,
+					srb->use_sg, &srb->resid);
+		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+		if (result == USB_STOR_XFER_ERROR)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		/* If the device tried to send back more data than the
+		 * amount requested, the spec requires us to transfer
+		 * the CSW anyway.  Since there's no point retrying the
+		 * the command, we'll return fake sense data indicating
+		 * Illegal Request, Invalid Field in CDB.
+		 */
+		if (result == USB_STOR_XFER_LONG)
+			fake_sense = 1;
+	}
+
+	/* See flow chart on pg 15 of the Bulk Only Transport spec for
+	 * an explanation of how this code works.
+	 */
+
+	/* get CSW for device status */
+	US_DEBUGP("Attempting to get CSW...\n");
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+
+	/* Some broken devices add unnecessary zero-length packets to the
+	 * end of their data transfers.  Such packets show up as 0-length
+	 * CSWs.  If we encounter such a thing, try to read the CSW again.
+	 */
+	if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+		US_DEBUGP("Received 0-length CSW; retrying...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+	}
+
+	/* did the attempt to read the CSW fail? */
+	if (result == USB_STOR_XFER_STALLED) {
+
+		/* get the status again */
+		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				bcs, US_BULK_CS_WRAP_LEN, NULL);
+	}
+
+	/* if we still have a failure at this point, we're in trouble */
+	US_DEBUGP("Bulk status result = %d\n", result);
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	/* check bulk status */
+	residue = le32_to_cpu(bcs->Residue);
+	US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
+			le32_to_cpu(bcs->Signature), bcs->Tag, 
+			residue, bcs->Status);
+	if (bcs->Tag != srb->serial_number || bcs->Status > US_BULK_STAT_PHASE) {
+		US_DEBUGP("Bulk logical error\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* Some broken devices report odd signatures, so we do not check them
+	 * for validity against the spec. We store the first one we see,
+	 * and check subsequent transfers for validity against this signature.
+	 */
+	if (!us->bcs_signature) {
+		us->bcs_signature = bcs->Signature;
+		if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN))
+			US_DEBUGP("Learnt BCS signature 0x%08X\n",
+					le32_to_cpu(us->bcs_signature));
+	} else if (bcs->Signature != us->bcs_signature) {
+		US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n",
+			  le32_to_cpu(bcs->Signature),
+			  le32_to_cpu(us->bcs_signature));
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* try to compute the actual residue, based on how much data
+	 * was really transferred and what the device tells us */
+	if (residue) {
+		if (!(us->flags & US_FL_IGNORE_RESIDUE)) {
+			residue = min(residue, transfer_length);
+			srb->resid = max(srb->resid, (int) residue);
+		}
+	}
+
+	/* based on the status code, we report good or bad */
+	switch (bcs->Status) {
+		case US_BULK_STAT_OK:
+			/* device babbled -- return fake sense data */
+			if (fake_sense) {
+				memcpy(srb->sense_buffer, 
+				       usb_stor_sense_invalidCDB, 
+				       sizeof(usb_stor_sense_invalidCDB));
+				return USB_STOR_TRANSPORT_NO_SENSE;
+			}
+
+			/* command good -- note that data could be short */
+			return USB_STOR_TRANSPORT_GOOD;
+
+		case US_BULK_STAT_FAIL:
+			/* command failed */
+			return USB_STOR_TRANSPORT_FAILED;
+
+		case US_BULK_STAT_PHASE:
+			/* phase error -- note that a transport reset will be
+			 * invoked by the invoke_transport() function
+			 */
+			return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	/* we should never get here, but if we do, we're in trouble */
+	return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+
+/* This is the common part of the device reset code.
+ *
+ * It's handy that every transport mechanism uses the control endpoint for
+ * resets.
+ *
+ * Basically, we send a reset with a 20-second timeout, so we don't get
+ * jammed attempting to do the reset.
+ */
+static int usb_stor_reset_common(struct us_data *us,
+		u8 request, u8 requesttype,
+		u16 value, u16 index, void *data, u16 size)
+{
+	int result;
+	int result2;
+	int rc = FAILED;
+
+	/* Let the SCSI layer know we are doing a reset, set the
+	 * RESETTING bit, and clear the ABORTING bit so that the reset
+	 * may proceed.
+	 */
+	scsi_lock(us_to_host(us));
+	usb_stor_report_device_reset(us);
+	set_bit(US_FLIDX_RESETTING, &us->flags);
+	clear_bit(US_FLIDX_ABORTING, &us->flags);
+	scsi_unlock(us_to_host(us));
+
+	/* A 20-second timeout may seem rather long, but a LaCie
+	 * StudioDrive USB2 device takes 16+ seconds to get going
+	 * following a powerup or USB attach event.
+	 */
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+			request, requesttype, value, index, data, size,
+			20*HZ);
+	if (result < 0) {
+		US_DEBUGP("Soft reset failed: %d\n", result);
+		goto Done;
+	}
+
+ 	/* Give the device some time to recover from the reset,
+ 	 * but don't delay disconnect processing. */
+ 	wait_event_interruptible_timeout(us->delay_wait,
+ 			test_bit(US_FLIDX_DISCONNECTING, &us->flags),
+ 			HZ*6);
+	if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		US_DEBUGP("Reset interrupted by disconnect\n");
+		goto Done;
+	}
+
+	US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
+	result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
+
+	US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
+	result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
+
+	/* return a result code based on the result of the control message */
+	if (result < 0 || result2 < 0) {
+		US_DEBUGP("Soft reset failed\n");
+		goto Done;
+	}
+	US_DEBUGP("Soft reset done\n");
+	rc = SUCCESS;
+
+  Done:
+	clear_bit(US_FLIDX_RESETTING, &us->flags);
+	return rc;
+}
+
+/* This issues a CB[I] Reset to the device in question
+ */
+#define CB_RESET_CMD_SIZE	12
+
+int usb_stor_CB_reset(struct us_data *us)
+{
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE);
+	us->iobuf[0] = SEND_DIAGNOSTIC;
+	us->iobuf[1] = 4;
+	return usb_stor_reset_common(us, US_CBI_ADSC, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, us->iobuf, CB_RESET_CMD_SIZE);
+}
+
+/* This issues a Bulk-only Reset to the device in question, including
+ * clearing the subsequent endpoint halts that may occur.
+ */
+int usb_stor_Bulk_reset(struct us_data *us)
+{
+	US_DEBUGP("%s called\n", __FUNCTION__);
+
+	return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, 
+				 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+				 0, us->ifnum, NULL, 0);
+}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
new file mode 100644
index 0000000..e25f8d8
--- /dev/null
+++ b/drivers/usb/storage/transport.h
@@ -0,0 +1,174 @@
+/* Driver for USB Mass Storage compliant devices
+ * Transport Functions Header File
+ *
+ * $Id: transport.h,v 1.18 2002/04/21 02:57:59 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <linux/config.h>
+#include <linux/blkdev.h>
+
+/* Protocols */
+
+#define US_PR_CBI	0x00		/* Control/Bulk/Interrupt */
+#define US_PR_CB	0x01		/* Control/Bulk w/o interrupt */
+#define US_PR_BULK	0x50		/* bulk only */
+#ifdef CONFIG_USB_STORAGE_USBAT
+#define US_PR_SCM_ATAPI	0x80		/* SCM-ATAPI bridge */
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR09
+#define US_PR_EUSB_SDDR09	0x81	/* SCM-SCSI bridge for SDDR-09 */
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+#define US_PR_SDDR55	0x82		/* SDDR-55 (made up) */
+#endif
+#define US_PR_DPCM_USB  0xf0		/* Combination CB/SDDR09 */
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#define US_PR_FREECOM   0xf1		/* Freecom */
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+#define US_PR_DATAFAB   0xf2		/* Datafab chipsets */
+#endif
+
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+#define US_PR_JUMPSHOT  0xf3		/* Lexar Jumpshot */
+#endif
+
+#define US_PR_DEVICE	0xff		/* Use device's value */
+
+/*
+ * Bulk only data structures
+ */
+
+/* command block wrapper */
+struct bulk_cb_wrap {
+	__le32	Signature;		/* contains 'USBC' */
+	__u32	Tag;			/* unique per command id */
+	__le32	DataTransferLength;	/* size of data */
+	__u8	Flags;			/* direction in bit 0 */
+	__u8	Lun;			/* LUN normally 0 */
+	__u8	Length;			/* of of the CDB */
+	__u8	CDB[16];		/* max command */
+};
+
+#define US_BULK_CB_WRAP_LEN	31
+#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
+#define US_BULK_FLAG_IN		1
+#define US_BULK_FLAG_OUT	0
+
+/* command status wrapper */
+struct bulk_cs_wrap {
+	__le32	Signature;		/* should = 'USBS' */
+	__u32	Tag;			/* same as original command */
+	__le32	Residue;		/* amount not transferred */
+	__u8	Status;			/* see below */
+	__u8	Filler[18];
+};
+
+#define US_BULK_CS_WRAP_LEN	13
+#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
+#define US_BULK_STAT_OK		0
+#define US_BULK_STAT_FAIL	1
+#define US_BULK_STAT_PHASE	2
+
+/* bulk-only class specific requests */
+#define US_BULK_RESET_REQUEST	0xff
+#define US_BULK_GET_MAX_LUN	0xfe
+
+/*
+ * usb_stor_bulk_transfer_xxx() return codes, in order of severity
+ */
+
+#define USB_STOR_XFER_GOOD	0	/* good transfer                 */
+#define USB_STOR_XFER_SHORT	1	/* transferred less than expected */
+#define USB_STOR_XFER_STALLED	2	/* endpoint stalled              */
+#define USB_STOR_XFER_LONG	3	/* device tried to send too much */
+#define USB_STOR_XFER_ERROR	4	/* transfer died in the middle   */
+
+/*
+ * Transport return codes
+ */
+
+#define USB_STOR_TRANSPORT_GOOD	   0   /* Transport good, command good	   */
+#define USB_STOR_TRANSPORT_FAILED  1   /* Transport good, command failed   */
+#define USB_STOR_TRANSPORT_NO_SENSE 2  /* Command failed, no auto-sense    */
+#define USB_STOR_TRANSPORT_ERROR   3   /* Transport bad (i.e. device dead) */
+
+/*
+ * We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
+ * return codes.  But now the transport and low-level transfer routines
+ * treat an abort as just another error (-ENOENT for a cancelled URB).
+ * It is up to the invoke_transport() function to test for aborts and
+ * distinguish them from genuine communication errors.
+ */
+
+/*
+ * CBI accept device specific command
+ */
+
+#define US_CBI_ADSC		0
+
+extern int usb_stor_CBI_transport(struct scsi_cmnd *, struct us_data*);
+
+extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*);
+extern int usb_stor_CB_reset(struct us_data*);
+
+extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*);
+extern int usb_stor_Bulk_max_lun(struct us_data*);
+extern int usb_stor_Bulk_reset(struct us_data*);
+
+extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*);
+extern void usb_stor_stop_transport(struct us_data*);
+
+extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size, int timeout);
+extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);
+
+extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size);
+extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+		void *buf, unsigned int length, unsigned int *act_len);
+extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
+		void *buf, unsigned int length, int use_sg, int *residual);
+
+#endif
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
new file mode 100644
index 0000000..d53f777
--- /dev/null
+++ b/drivers/usb/storage/unusual_devs.h
@@ -0,0 +1,986 @@
+/* Driver for USB Mass Storage compliant devices
+ * Ununsual Devices File
+ *
+ * $Id: unusual_devs.h,v 1.32 2002/02/25 02:41:24 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ *   (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* IMPORTANT NOTE: This file must be included in another file which does
+ * the following thing for it to work:
+ * The macro UNUSUAL_DEV() must be defined before this file is included
+ */
+#include <linux/config.h>
+
+/* If you edit this file, please try to keep it sorted first by VendorID,
+ * then by ProductID.
+ *
+ * If you want to add an entry for this file, be sure to include the
+ * following information:
+ *	- a patch that adds the entry for your device, including your
+ *	  email address right above the entry (plus maybe a brief
+ *	  explanation of the reason for the entry),
+ *	- a copy of /proc/bus/usb/devices with your device plugged in
+ *	  running with this patch.
+ * Send your submission to either Phil Dibowitz <phil@ipom.com> or
+ * Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
+ * USB development list <linux-usb-devel@lists.sourceforge.net>.
+ */
+
+UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0100,
+		"Mitsumi",
+		"USB FDD",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200, 
+		"HP",
+		"CD-Writer+",
+		US_SC_8070, US_PR_CB, NULL, 0), 
+
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV(  0x03f0, 0x0207, 0x0001, 0x0001, 
+		"HP",
+		"CD-Writer+ 8200e",
+		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
+
+UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001, 
+		"HP",
+		"CD-Writer+ CD-4e",
+		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
+#endif
+
+/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
+ * always fails and confuses drive.
+ */
+UNUSUAL_DEV(  0x0411, 0x001c, 0x0113, 0x0113,
+		"Buffalo",
+		"DUB-P40G HDD",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate (DPCM_USB)",
+ 		US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
+#endif
+
+/* Patch submitted by Philipp Friedrich <philipp@void.at> */
+UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S3x",
+		US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch submitted by Philipp Friedrich <philipp@void.at> */
+UNUSUAL_DEV(  0x0482, 0x0101, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S4",
+		US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch submitted by Stephane Galles <stephane.galles@free.fr> */
+UNUSUAL_DEV(  0x0482, 0x0103, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S5",
+		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch for Kyocera Finecam L3
+ * Submitted by Michael Krauth <michael.krauth@web.de>
+ * and Alessandro Fracchetti <al.fracchetti@tin.it>
+ */
+UNUSUAL_DEV(  0x0482, 0x0105, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam L3",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY),
+
+/* Reported by Paul Stewart <stewart@wetlogic.net>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x0001,
+		"Hitachi",
+		"DVD-CAM DZ-MV100A Camcorder",
+		US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
+
+/* Reported by Andreas Bockhold <andreas@bockionline.de> */
+UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D70",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* BENQ DC5330
+ * Reported by Manuel Fombuena <mfombuena@ya.com> and
+ * Frank Copeland <fjc@thingy.apana.org.au> */
+UNUSUAL_DEV(  0x04a5, 0x3010, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Simon Levitt <simon@whattf.com>
+ * This entry needs Sub and Proto fields */
+UNUSUAL_DEV(  0x04b8, 0x0601, 0x0100, 0x0100,
+		"Epson",
+		"875DC Storage",
+		US_SC_SCSI, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/* Reported by Khalid Aziz <khalid@gonehiking.org>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x04b8, 0x0602, 0x0110, 0x0110,
+		"Epson",
+		"785EPX Storage",
+		US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN),
+
+/* Not sure who reported this originally but
+ * Pavel Machek <pavel@ucw.cz> reported that the extra US_FL_SINGLE_LUN
+ * flag be added */
+UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
+		"Fujifilm",
+		"FinePix 1400Zoom",
+		US_SC_UFI, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN),
+
+/* Reported by Peter Wächtler <pwaechtler@loewe-komp.de>
+ * The device needs the flags only.
+ */
+UNUSUAL_DEV(  0x04ce, 0x0002, 0x0074, 0x0074,
+		"ScanLogic",
+		"SL11R-IDE",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY),
+
+/* Reported by Kriston Fincher <kriston@airmail.net>
+ * Patch submitted by Sean Millichamp <sean@bruenor.org>
+ * This is to support the Panasonic PalmCam PV-SD4090
+ * This entry is needed because the device reports Sub=ff 
+ */
+UNUSUAL_DEV(  0x04da, 0x0901, 0x0100, 0x0200,
+		"Panasonic",
+		"LS-120 Camera",
+		US_SC_UFI, US_PR_DEVICE, NULL, 0),
+
+/* From Yukihiro Nakai, via zaitcev@yahoo.com.
+ * This is needed for CB instead of CBI */
+UNUSUAL_DEV(  0x04da, 0x0d05, 0x0000, 0x0000,
+		"Sharp CE-CW05",
+		"CD-R/RW Drive",
+		US_SC_8070, US_PR_CB, NULL, 0),
+
+/* Reported by Adriaan Penning <a.penning@luon.net> */
+UNUSUAL_DEV(  0x04da, 0x2372, 0x0000, 0x9999,
+		"Panasonic",
+		"DMC-LCx Camera",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
+
+/* Most of the following entries were developed with the help of
+ * Shuttle/SCM directly.
+ */
+UNUSUAL_DEV(  0x04e6, 0x0001, 0x0200, 0x0200, 
+		"Matshita",
+		"LS-120",
+		US_SC_8020, US_PR_CB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x0002, 0x0100, 0x0100, 
+		"Shuttle",
+		"eUSCSI Bridge",
+		US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init, 
+		US_FL_SCM_MULT_TARG ), 
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+UNUSUAL_DEV(  0x04e6, 0x0003, 0x0000, 0x9999, 
+		"Sandisk",
+		"ImageMate SDDR09",
+		US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* This entry is from Andries.Brouwer@cwi.nl */
+UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,
+		"SCM Microsystems",
+		"eUSB SmartMedia / CompactFlash Adapter",
+		US_SC_SCSI, US_PR_DPCM_USB, sddr09_init, 
+		0), 
+#endif
+
+/* Reported by Markus Demleitner <msdemlei@cl.uni-heidelberg.de> */
+UNUSUAL_DEV(  0x04e6, 0x0006, 0x0100, 0x0100, 
+		"SCM Microsystems Inc.",
+		"eUSB MMC Adapter",
+		US_SC_SCSI, US_PR_CB, NULL, 
+		US_FL_SINGLE_LUN), 
+
+/* Reported by Daniel Nouri <dpunktnpunkt@web.de> */
+UNUSUAL_DEV(  0x04e6, 0x0006, 0x0205, 0x0205, 
+		"Shuttle",
+		"eUSB MMC Adapter",
+		US_SC_SCSI, US_PR_DEVICE, NULL, 
+		US_FL_SINGLE_LUN), 
+
+UNUSUAL_DEV(  0x04e6, 0x0007, 0x0100, 0x0200, 
+		"Sony",
+		"Hifd",
+		US_SC_SCSI, US_PR_CB, NULL, 
+		US_FL_SINGLE_LUN), 
+
+UNUSUAL_DEV(  0x04e6, 0x0009, 0x0200, 0x0200, 
+		"Shuttle",
+		"eUSB ATA/ATAPI Adapter",
+		US_SC_8020, US_PR_CB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x000a, 0x0200, 0x0200, 
+		"Shuttle",
+		"eUSB CompactFlash Adapter",
+		US_SC_8020, US_PR_CB, NULL, 0),
+
+UNUSUAL_DEV(  0x04e6, 0x000B, 0x0100, 0x0100, 
+		"Shuttle",
+		"eUSCSI Bridge",
+		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, 
+		US_FL_SCM_MULT_TARG ), 
+
+UNUSUAL_DEV(  0x04e6, 0x000C, 0x0100, 0x0100, 
+		"Shuttle",
+		"eUSCSI Bridge",
+		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, 
+		US_FL_SCM_MULT_TARG ), 
+
+UNUSUAL_DEV(  0x04e6, 0x0101, 0x0200, 0x0200, 
+		"Shuttle",
+		"CD-RW Device",
+		US_SC_8020, US_PR_CB, NULL, 0),
+
+/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
+ * Device uses standards-violating 32-byte Bulk Command Block Wrappers and
+ * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011.
+ */
+
+UNUSUAL_DEV(  0x04fc, 0x80c2, 0x0100, 0x0100,
+		"Kobian Mercury",
+		"Binocam DCB-132",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_BULK32),
+
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
+		"SCM",
+		"SCM USBAT-02",
+		US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
+		US_FL_SINGLE_LUN),
+#endif
+
+/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
+UNUSUAL_DEV(  0x050d, 0x0115, 0x0133, 0x0133,
+		"Belkin",
+		"USB SCSI Adaptor",
+		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/* Iomega Clik! Drive 
+ * Reported by David Chatenay <dchatenay@hotmail.com>
+ * The reason this is needed is not fully known.
+ */
+UNUSUAL_DEV(  0x0525, 0xa140, 0x0100, 0x0100,
+		"Iomega",
+		"USB Clik! 40",
+		US_SC_8070, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Yakumo Mega Image 37
+ * Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */
+UNUSUAL_DEV(  0x052b, 0x1801, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Another Yakumo camera.
+ * Reported by Michele Alzetta <michele.alzetta@aliceposta.it> */
+UNUSUAL_DEV(  0x052b, 0x1804, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Iacopo Spalletti <avvisi@spalletti.it> */
+UNUSUAL_DEV(  0x052b, 0x1807, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"300_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Yakumo Mega Image 47
+ * Reported by Bjoern Paetzel <kolrabi@kolrabi.de> */
+UNUSUAL_DEV(  0x052b, 0x1905, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"400_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Paul Ortyl <ortylp@3miasto.net>
+ * Note that it's similar to the device above, only different prodID */
+UNUSUAL_DEV(  0x052b, 0x1911, 0x0100, 0x0100,
+		"Tekom Technologies, Inc",
+		"400_CAMERA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0450, 
+		"Sony",
+		"DSC-S30/S70/S75/505V/F505/F707/F717/P8", 
+		US_SC_SCSI, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
+
+/* This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0500, 0x0500, 
+               "Sony",
+               "DSC-T1", 
+               US_SC_8070, US_PR_DEVICE, NULL,
+               US_FL_SINGLE_LUN ),
+
+
+/* Reported by wim@geeks.nl */
+UNUSUAL_DEV(  0x054c, 0x0025, 0x0100, 0x0100, 
+		"Sony",
+		"Memorystick NW-MS7",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+#ifdef CONFIG_USB_STORAGE_ISD200
+UNUSUAL_DEV(  0x054c, 0x002b, 0x0100, 0x0110,
+		"Sony",
+		"Portable USB Harddrive V2",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
+#endif
+
+/* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x0501,
+		"Sony",
+		"USB Floppy Drive",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x054c, 0x002d, 0x0100, 0x0100, 
+		"Sony",
+		"Memorystick MSAC-US1",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Klaus Mueller <k.mueller@intershop.de> */
+UNUSUAL_DEV(  0x054c, 0x002e, 0x0106, 0x0310, 
+		"Sony",
+		"Handycam",
+		US_SC_SCSI, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Rajesh Kumble Nayak <nayak@obs-nice.fr> */
+UNUSUAL_DEV(  0x054c, 0x002e, 0x0500, 0x0500, 
+		"Sony",
+		"Handycam HC-85",
+		US_SC_UFI, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x054c, 0x0032, 0x0000, 0x9999,
+		"Sony",
+		"Memorystick MSC-U01N",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Michal Mlotek <mlotek@foobar.pl> */
+UNUSUAL_DEV(  0x054c, 0x0058, 0x0000, 0x9999,
+		"Sony",
+		"PEG N760c Memorystick",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+		
+UNUSUAL_DEV(  0x054c, 0x0069, 0x0000, 0x9999,
+		"Sony",
+		"Memorystick MSC-U03",
+		US_SC_UFI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+
+/* Submitted by Nathan Babb <nathan@lexi.com> */
+UNUSUAL_DEV(  0x054c, 0x006d, 0x0000, 0x9999,
+		"Sony",
+		"PEG Mass Storage",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Submitted by Mike Alborn <malborn@deandra.homeip.net> */
+UNUSUAL_DEV(  0x054c, 0x016a, 0x0000, 0x9999,
+		"Sony",
+		"PEG Mass Storage",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+		
+/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
+UNUSUAL_DEV(  0x054c, 0x0099, 0x0000, 0x9999,
+                "Sony",
+                "PEG Mass Storage",
+                US_SC_DEVICE, US_PR_DEVICE, NULL,
+                US_FL_FIX_INQUIRY ),
+
+		
+UNUSUAL_DEV(  0x057b, 0x0000, 0x0000, 0x0299, 
+		"Y-E Data",
+		"Flashbuster-U",
+		US_SC_DEVICE,  US_PR_CB, NULL,
+		US_FL_SINGLE_LUN),
+
+UNUSUAL_DEV(  0x057b, 0x0000, 0x0300, 0x9999, 
+		"Y-E Data",
+		"Flashbuster-U",
+		US_SC_DEVICE,  US_PR_DEVICE, NULL,
+		US_FL_SINGLE_LUN),
+
+/* Reported by Johann Cardon <johann.cardon@free.fr>
+ * This entry is needed only because the device reports
+ * bInterfaceClass = 0xff (vendor-specific)
+ */
+UNUSUAL_DEV(  0x057b, 0x0022, 0x0000, 0x9999, 
+		"Y-E Data",
+		"Silicon Media R/W",
+		US_SC_DEVICE, US_PR_DEVICE, NULL, 0),
+
+/* Fabrizio Fellini <fello@libero.it> */
+UNUSUAL_DEV(  0x0595, 0x4343, 0x0000, 0x2210,
+		"Fujifilm",
+		"Digital Camera EX-20 DSC",
+		US_SC_8070, US_PR_DEVICE, NULL, 0 ),
+
+/* The entry was here before I took over, and had US_SC_RBC. It turns
+ * out that isn't needed. Additionally, Torsten Eriksson
+ * <Torsten.Eriksson@bergianska.se> is able to use his device fine
+ * without this entry at all - but I don't suspect that will be true
+ * for all users (the protocol is likely needed), so is staying at
+ * this time. - Phil Dibowitz <phil@ipom.com>
+ */
+UNUSUAL_DEV(  0x059f, 0xa601, 0x0200, 0x0200, 
+		"LaCie",
+		"USB Hard Disk",
+		US_SC_DEVICE, US_PR_CB, NULL, 0 ),
+
+/* Submitted by Joel Bourquard <numlock@freesurf.ch>
+ * Some versions of this device need the SubClass and Protocol overrides
+ * while others don't.
+ */
+UNUSUAL_DEV(  0x05ab, 0x0060, 0x1104, 0x1110,
+		"In-System",
+		"PyroGate External CD-ROM Enclosure (FCD-523)",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_NEED_OVERRIDE ),
+
+#ifdef CONFIG_USB_STORAGE_ISD200
+UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
+		"In-System",
+		"USB/IDE Bridge (ATA/ATAPI)",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x0301, 0x0100, 0x0110,
+		"In-System",
+		"Portable USB Harddrive V2",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x0351, 0x0100, 0x0110,
+		"In-System",
+		"Portable USB Harddrive V2",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x5701, 0x0100, 0x0110,
+		"In-System",
+		"USB Storage Adapter V2",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
+#endif
+
+/* Reported by Avi Kivity <avi@argo.co.il> */
+UNUSUAL_DEV( 0x05ac, 0x1203, 0x0001, 0x0001,
+		"Apple",
+		"iPod",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+UNUSUAL_DEV( 0x05ac, 0x1205, 0x0001, 0x0001,
+		"Apple",
+		"iPod",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+UNUSUAL_DEV(  0x05dc, 0x0001, 0x0000, 0x0001,
+		"Lexar",
+		"Jumpshot USB CF Reader",
+		US_SC_SCSI, US_PR_JUMPSHOT, NULL,
+		US_FL_NEED_OVERRIDE ),
+#endif
+
+/* Reported by Blake Matheny <bmatheny@purdue.edu> */
+UNUSUAL_DEV(  0x05dc, 0xb002, 0x0000, 0x0113,
+		"Lexar",
+		"USB CF Reader",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* The following two entries are for a Genesys USB to IDE
+ * converter chip, but it changes its ProductId depending
+ * on whether or not a disk or an optical device is enclosed
+ * They were originally reported by Alexander Oltu
+ * <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
+ * respectively.
+ */
+UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Optical",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
+UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
+		"Genesys Logic",
+		"USB to IDE Disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
+/* Reported by Hanno Boeck <hanno@gmx.de>
+ * Taken from the Lycoris Kernel */
+UNUSUAL_DEV(  0x0636, 0x0003, 0x0000, 0x9999,
+		"Vivitar",
+		"Vivicam 35Xx",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
+UNUSUAL_DEV(  0x0644, 0x0000, 0x0100, 0x0100, 
+		"TEAC",
+		"Floppy Drive",
+		US_SC_UFI, US_PR_CB, NULL, 0 ), 
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+UNUSUAL_DEV(  0x066b, 0x0105, 0x0100, 0x0100, 
+		"Olympus",
+		"Camedia MAUSB-2",
+		US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+		US_FL_SINGLE_LUN ),
+#endif
+
+/* Reported by Darsen Lu <darsen@micro.ee.nthu.edu.tw> */
+UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001,
+		"SigmaTel",
+		"USBMSC Audio Player",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/* Reported by Richard -=[]=- <micro_flyer@hotmail.com> */
+UNUSUAL_DEV( 0x067b, 0x2507, 0x0100, 0x0100,
+		"Prolific Technology Inc.",
+		"Mass Storage Device",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
+
+/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
+UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
+		"Prolific Technology Inc.",
+		"ATAPI-6 Bridge Controller",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
+
+/* Submitted by Benny Sjostrand <benny@hostmobility.com> */
+UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
+		"Minolta",
+		"Dimage F300",
+		US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+
+/* Reported by Miguel A. Fosas <amn3s1a@ono.com> */
+UNUSUAL_DEV(  0x0686, 0x4017, 0x0001, 0x0001,
+                "Minolta",
+                "DIMAGE E223",
+                US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
+
+UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
+		"Hagiwara",
+		"FlashGate SmartMedia",
+		US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+
+UNUSUAL_DEV(  0x0693, 0x0005, 0x0100, 0x0100,
+		"Hagiwara",
+		"Flashgate",
+		US_SC_SCSI, US_PR_BULK, NULL, 0 ), 
+
+UNUSUAL_DEV(  0x0781, 0x0001, 0x0200, 0x0200, 
+		"Sandisk",
+		"ImageMate SDDR-05a",
+		US_SC_SCSI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV(  0x0781, 0x0100, 0x0100, 0x0100,
+		"Sandisk",
+		"ImageMate SDDR-12",
+		US_SC_SCSI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+UNUSUAL_DEV(  0x0781, 0x0200, 0x0000, 0x9999, 
+		"Sandisk",
+		"ImageMate SDDR-09",
+		US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
+		US_FL_SINGLE_LUN ),
+#endif
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+UNUSUAL_DEV(  0x07ab, 0xfc01, 0x0000, 0x9999,
+		"Freecom",
+		"USB-IDE",
+		US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
+#endif
+
+/* Reported by Eero Volotinen <eero@ping-viini.org> */
+UNUSUAL_DEV(  0x07ab, 0xfccd, 0x0406, 0x0406,
+		"Freecom Technologies",
+		"FHD-Classic",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0133, 
+		"Microtech",
+		"USB-SCSI-DB25",
+		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ), 
+
+UNUSUAL_DEV(  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
+UNUSUAL_DEV(  0x07af, 0x0006, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate (DPCM_USB)",
+ 		US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+UNUSUAL_DEV(  0x07c4, 0xa000, 0x0000, 0x0015,
+		"Datafab",
+		"MDCFE-B USB CF Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+
+/*
+ * The following Datafab-based devices may or may not work
+ * using the current driver...the 0xffff is arbitrary since I
+ * don't know what device versions exist for these guys.
+ *
+ * The 0xa003 and 0xa004 devices in particular I'm curious about.
+ * I'm told they exist but so far nobody has come forward to say that
+ * they work with this driver.  Given the success we've had getting
+ * other Datafab-based cards operational with this driver, I've decided
+ * to leave these two devices in the list.
+ */
+UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff,
+		"SIIG/Datafab",
+		"SIIG/Datafab Memory Stick+CF Reader/Writer",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+
+/* Reported by Josef Reisinger <josef.reisinger@netcologne.de> */
+UNUSUAL_DEV( 0x07c4, 0xa002, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"MD2/MD3 Disk enclosure",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_SINGLE_LUN ),
+
+UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"Datafab-based Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"Datafab-based Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
+		"PNY/Datafab",
+		"PNY/Datafab CF+SM Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+
+UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
+		"Simple Tech/Datafab",
+		"Simple Tech/Datafab CF+SM Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+#endif
+		
+#ifdef CONFIG_USB_STORAGE_SDDR55
+/* Contributed by Peter Waechtler */
+UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999,
+		"Datafab",
+		"MDSM-B reader",
+		US_SC_SCSI, US_PR_SDDR55, NULL,
+		US_FL_FIX_INQUIRY ),
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+/* Submitted by Olaf Hering <olh@suse.de> */
+UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0xffff,
+		"Datafab Systems, Inc.",
+		"USB to CF + SM Combo (LC1)",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		0 ),
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+/* SM part - aeb <Andries.Brouwer@cwi.nl> */
+UNUSUAL_DEV(  0x07c4, 0xa109, 0x0000, 0xffff,
+		"Datafab Systems, Inc.",
+		"USB to CF + SM Combo (LC1)",
+		US_SC_SCSI, US_PR_SDDR55, NULL,
+		US_FL_SINGLE_LUN ),
+#endif
+
+/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100
+ * Only revision 1.13 tested (same for all of the above devices,
+ * based on the Datafab DF-UG-07 chip).  Needed for US_FL_FIX_INQUIRY.
+ * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>.
+ * See also http://martin.wilck.bei.t-online.de/#kecf .
+ */
+UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0xffff,
+		"Datafab",
+		"KECF-USB",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
+ * to the USB storage specification in two ways:
+ * - They tell us they are using transport protocol CBI. In reality they
+ *   are using transport protocol CB.
+ * - They don't like the INQUIRY command. So we must handle this command
+ *   of the SCSI layer ourselves.
+ * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have
+ *   bInterfaceProtocol=0x00 (US_PR_CBI) while others have 0x01 (US_PR_CB).
+ *   So don't remove the US_PR_CB override!
+ * - Cameras with bcdDevice=0x9009 require the US_SC_8070 override.
+ */
+UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999,
+		"Casio",
+		"QV DigitalCamera",
+		US_SC_8070, US_PR_CB, NULL,
+		US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ),
+
+/* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/
+UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001,
+		"Samsung",
+		"Digimax 410",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY),
+
+/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
+ * Flag will support Bulk devices which use a standards-violating 32-byte
+ * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with
+ * Grandtech GT892x chip, which request "Proprietary SCSI Bulk" support.
+ */
+
+UNUSUAL_DEV(  0x084d, 0x0011, 0x0110, 0x0110,
+		"Grandtech",
+		"DC2MEGA",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_BULK32),
+
+
+/* Entry needed for flags. Moreover, all devices with this ID use
+ * bulk-only transport, but _some_ falsely report Control/Bulk instead.
+ * One example is "Trumpion Digital Research MYMP3".
+ * Submitted by Bjoern Brill <brill(at)fs.math.uni-frankfurt.de>
+ */
+UNUSUAL_DEV(  0x090a, 0x1001, 0x0100, 0x0100,
+		"Trumpion",
+		"t33520 USB Flash Card Controller",
+		US_SC_DEVICE, US_PR_BULK, NULL,
+		US_FL_NEED_OVERRIDE ),
+
+/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */
+UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
+		"Trumpion",
+		"MP3 player",
+		US_SC_RBC, US_PR_BULK, NULL,
+		0 ),
+
+/* aeb */
+UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
+		"Feiya",
+		"5-in-1 Card Reader",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
+/* This Pentax still camera is not conformant
+ * to the USB storage specification: -
+ * - It does not like the INQUIRY command. So we must handle this command
+ *   of the SCSI layer ourselves.
+ * Tested on Rev. 10.00 (0x1000)
+ * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
+ */
+UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
+                "Pentax",
+                "Optio 2/3/400",
+                US_SC_DEVICE, US_PR_DEVICE, NULL,
+                US_FL_FIX_INQUIRY ),
+
+
+/* Submitted by Per Winkvist <per.winkvist@uk.com> */
+UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
+                "Pentax",
+                "Optio S/S4",
+                US_SC_DEVICE, US_PR_DEVICE, NULL,
+                US_FL_FIX_INQUIRY ),
+		
+#ifdef CONFIG_USB_STORAGE_ISD200
+UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
+		"ATI",
+		"USB Cable 205",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
+	       "Acomdata",
+	       "CF",
+	       US_SC_SCSI, US_PR_DATAFAB, NULL,
+	       US_FL_SINGLE_LUN ),
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
+	       "Acomdata",
+	       "SM",
+	       US_SC_SCSI, US_PR_SDDR55, NULL,
+	       US_FL_SINGLE_LUN ),
+#endif
+
+/* Submitted by Joris Struyve <joris@struyve.be> */
+UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
+		"Medion",
+		"MD 7425",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY),
+
+/*
+ * Entry for Jenoptik JD 5200z3
+ *
+ * email: car.busse@gmx.de
+ */
+UNUSUAL_DEV(  0x0d96, 0x5200, 0x0001, 0x0200,
+		"Jenoptik",
+		"JD 5200 z3",
+		US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+
+/* Reported by Lubomir Blaha <tritol@trilogic.cz>
+ * I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this
+ * works for me. Can anybody correct these values? (I able to test corrected
+ * version.)
+ */
+UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff,
+		"Netac",
+		"USB-CF-Card",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Patch by Stephan Walter <stephan.walter@epfl.ch>
+ * I don't know why, but it works... */
+UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012,
+		"WINWARD",
+		"Music Disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Ian McConnell <ian at emit.demon.co.uk> */
+UNUSUAL_DEV(  0x0dda, 0x0301, 0x0012, 0x0012,
+		"PNP_MP3",
+		"PNP_MP3 PLAYER",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */
+UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300,
+		"USB",
+		"Solid state disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_INQUIRY ),
+
+/* Submitted by Daniel Drake <dsd@gentoo.org>
+ * Reported by dayul on the Gentoo Forums */
+UNUSUAL_DEV(  0x0ea0, 0x2168, 0x0110, 0x0110,
+		"Ours Technology",
+		"Flash Disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Rastislav Stanik <rs_kernel@yahoo.com> */
+UNUSUAL_DEV(  0x0ea0, 0x6828, 0x0110, 0x0110,
+		"USB",
+		"Flash Disk",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Michael Stattmann <michael@stattmann.com> */
+UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"V800-Vodafone 802",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_NO_WP_DETECT ),
+
+/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
+ * Tested on hardware version 1.10.
+ * Entry is needed only for the initializer function override.
+ */
+UNUSUAL_DEV(  0x1019, 0x0c55, 0x0000, 0x9999,
+		"Desknote",
+		"UCR-61S2B",
+		US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
+		0 ),
+
+/* Reported by Kotrla Vitezslav <kotrla@ceb.cz> */
+UNUSUAL_DEV(  0x1370, 0x6828, 0x0110, 0x0110,
+		"SWISSBIT",
+		"Black Silver",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
+UNUSUAL_DEV(  0x2735, 0x100b, 0x0000, 0x9999,
+		"MPIO",
+		"HS200",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_GO_SLOW ),
+
+#ifdef CONFIG_USB_STORAGE_SDDR55
+UNUSUAL_DEV(  0x55aa, 0xa103, 0x0000, 0x9999, 
+		"Sandisk",
+		"ImageMate SDDR55",
+		US_SC_SCSI, US_PR_SDDR55, NULL,
+		US_FL_SINGLE_LUN),
+#endif
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
new file mode 100644
index 0000000..35c1ca6
--- /dev/null
+++ b/drivers/usb/storage/usb.c
@@ -0,0 +1,1051 @@
+/* Driver for USB Mass Storage compliant devices
+ *
+ * $Id: usb.c,v 1.75 2002/04/22 03:39:43 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Developed with the assistance of:
+ *   (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
+ *   (c) 2003 Alan Stern (stern@rowland.harvard.edu)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+#include "protocol.h"
+#include "debug.h"
+#include "initializers.h"
+
+#ifdef CONFIG_USB_STORAGE_USBAT
+#include "shuttle_usbat.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR09
+#include "sddr09.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR55
+#include "sddr55.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_DPCM
+#include "dpcm.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_FREECOM
+#include "freecom.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_ISD200
+#include "isd200.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+#include "datafab.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+#include "jumpshot.h"
+#endif
+
+
+/* Some informational data */
+MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
+MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
+MODULE_LICENSE("GPL");
+
+static unsigned int delay_use = 5;
+module_param(delay_use, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
+
+
+/* These are used to make sure the module doesn't unload before all the
+ * threads have exited.
+ */
+static atomic_t total_threads = ATOMIC_INIT(0);
+static DECLARE_COMPLETION(threads_gone);
+
+
+static int storage_probe(struct usb_interface *iface,
+			 const struct usb_device_id *id);
+
+static void storage_disconnect(struct usb_interface *iface);
+
+/* 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[].
+ */
+
+#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_FIX_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 */
+	{ NULL }
+};
+
+static struct usb_driver usb_storage_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"usb-storage",
+	.probe =	storage_probe,
+	.disconnect =	storage_disconnect,
+	.id_table =	storage_usb_ids,
+};
+
+/*
+ * 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)
+{
+	if (data_len<36) // You lose.
+		return;
+
+	if(data[0]&0x20) { /* USB device currently not connected. Return
+			      peripheral qualifier 001b ("...however, the
+			      physical device is not currently connected
+			      to this logical unit") and leave vendor and
+			      product identification empty. ("If the target
+			      does store some of the INQUIRY data on the
+			      device, it may return zeros or ASCII spaces 
+			      (20h) in those fields until the data is
+			      available from the device."). */
+		memset(data+8,0,28);
+	} else {
+		u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);
+		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 + ((bcdDevice>>12) & 0x0F);
+		data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
+		data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
+		data[35] = 0x30 + ((bcdDevice) & 0x0F);
+	}
+
+	usb_stor_set_xfer_buf(data, data_len, us->srb);
+}
+
+static int usb_stor_control_thread(void * __us)
+{
+	struct us_data *us = (struct us_data *)__us;
+	struct Scsi_Host *host = us_to_host(us);
+
+	lock_kernel();
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources.
+	 */
+	daemonize("usb-storage");
+	current->flags |= PF_NOFREEZE;
+	unlock_kernel();
+
+	/* acquire a reference to the host, so it won't be deallocated
+	 * until we're ready to exit */
+	scsi_host_get(host);
+
+	/* signal that we've started the thread */
+	complete(&(us->notify));
+
+	for(;;) {
+		US_DEBUGP("*** thread sleeping.\n");
+		if(down_interruptible(&us->sema))
+			break;
+			
+		US_DEBUGP("*** thread awakened.\n");
+
+		/* lock the device pointers */
+		down(&(us->dev_semaphore));
+
+		/* if the device has disconnected, we are free to exit */
+		if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+			US_DEBUGP("-- exiting\n");
+			up(&(us->dev_semaphore));
+			break;
+		}
+
+		/* lock access to the state */
+		scsi_lock(host);
+
+		/* has the command timed out *already* ? */
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
+			us->srb->result = DID_ABORT << 16;
+			goto SkipForAbort;
+		}
+
+		scsi_unlock(host);
+
+		/* reject the command if the direction indicator 
+		 * is UNKNOWN
+		 */
+		if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
+			US_DEBUGP("UNKNOWN data direction\n");
+			us->srb->result = DID_ERROR << 16;
+		}
+
+		/* reject if target != 0 or if LUN is higher than
+		 * the maximum known LUN
+		 */
+		else if (us->srb->device->id && 
+				!(us->flags & US_FL_SCM_MULT_TARG)) {
+			US_DEBUGP("Bad target number (%d:%d)\n",
+				  us->srb->device->id, us->srb->device->lun);
+			us->srb->result = DID_BAD_TARGET << 16;
+		}
+
+		else if (us->srb->device->lun > us->max_lun) {
+			US_DEBUGP("Bad LUN (%d:%d)\n",
+				  us->srb->device->id, us->srb->device->lun);
+			us->srb->result = DID_BAD_TARGET << 16;
+		}
+
+		/* Handle those devices which need us to fake 
+		 * their inquiry data */
+		else if ((us->srb->cmnd[0] == INQUIRY) &&
+			    (us->flags & US_FL_FIX_INQUIRY)) {
+			unsigned char data_ptr[36] = {
+			    0x00, 0x80, 0x02, 0x02,
+			    0x1F, 0x00, 0x00, 0x00};
+
+			US_DEBUGP("Faking INQUIRY command\n");
+			fill_inquiry_response(us, data_ptr, 36);
+			us->srb->result = SAM_STAT_GOOD;
+		}
+
+		/* we've got a command, let's do it! */
+		else {
+			US_DEBUG(usb_stor_show_command(us->srb));
+			us->proto_handler(us->srb, us);
+		}
+
+		/* lock access to the state */
+		scsi_lock(host);
+
+		/* indicate that the command is done */
+		if (us->srb->result != DID_ABORT << 16) {
+			US_DEBUGP("scsi cmd done, result=0x%x\n", 
+				   us->srb->result);
+			us->srb->scsi_done(us->srb);
+		} else {
+SkipForAbort:
+			US_DEBUGP("scsi command aborted\n");
+		}
+
+		/* If an abort request was received we need to signal that
+		 * the abort has finished.  The proper test for this is
+		 * the TIMED_OUT flag, not srb->result == DID_ABORT, because
+		 * a timeout/abort request might be received after all the
+		 * USB processing was complete. */
+		if (test_bit(US_FLIDX_TIMED_OUT, &us->flags))
+			complete(&(us->notify));
+
+		/* finished working on this command */
+		us->srb = NULL;
+		scsi_unlock(host);
+
+		/* unlock the device pointers */
+		up(&(us->dev_semaphore));
+	} /* for (;;) */
+
+	scsi_host_put(host);
+
+	/* notify the exit routine that we're actually exiting now 
+	 *
+	 * complete()/wait_for_completion() is similar to up()/down(),
+	 * except that complete() is safe in the case where the structure
+	 * is getting deleted in a parallel mode of execution (i.e. just
+	 * after the down() -- that's necessary for the thread-shutdown
+	 * case.
+	 *
+	 * complete_and_exit() goes even further than this -- it is safe in
+	 * the case that the thread of the caller is going away (not just
+	 * the structure) -- this is necessary for the module-remove case.
+	 * This is important in preemption kernels, which transfer the flow
+	 * of execution immediately upon a complete().
+	 */
+	complete_and_exit(&threads_gone, 0);
+}	
+
+/***********************************************************************
+ * Device probing and disconnecting
+ ***********************************************************************/
+
+/* Associate our private data with the USB device */
+static int associate_dev(struct us_data *us, struct usb_interface *intf)
+{
+	US_DEBUGP("-- %s\n", __FUNCTION__);
+
+	/* Fill in the device-related fields */
+	us->pusb_dev = interface_to_usbdev(intf);
+	us->pusb_intf = intf;
+	us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+	US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
+			le16_to_cpu(us->pusb_dev->descriptor.idVendor),
+			le16_to_cpu(us->pusb_dev->descriptor.idProduct),
+			le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));
+	US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
+			intf->cur_altsetting->desc.bInterfaceSubClass,
+			intf->cur_altsetting->desc.bInterfaceProtocol);
+
+	/* Store our private data in the interface */
+	usb_set_intfdata(intf, us);
+
+	/* Allocate the device-related DMA-mapped buffers */
+	us->cr = usb_buffer_alloc(us->pusb_dev, sizeof(*us->cr),
+			GFP_KERNEL, &us->cr_dma);
+	if (!us->cr) {
+		US_DEBUGP("usb_ctrlrequest allocation failed\n");
+		return -ENOMEM;
+	}
+
+	us->iobuf = usb_buffer_alloc(us->pusb_dev, US_IOBUF_SIZE,
+			GFP_KERNEL, &us->iobuf_dma);
+	if (!us->iobuf) {
+		US_DEBUGP("I/O buffer allocation failed\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+/* Get the unusual_devs entries and the string descriptors */
+static void get_device_info(struct us_data *us, int id_index)
+{
+	struct usb_device *dev = us->pusb_dev;
+	struct usb_interface_descriptor *idesc =
+		&us->pusb_intf->cur_altsetting->desc;
+	struct us_unusual_dev *unusual_dev = &us_unusual_dev_list[id_index];
+	struct usb_device_id *id = &storage_usb_ids[id_index];
+
+	/* Store the entries */
+	us->unusual_dev = unusual_dev;
+	us->subclass = (unusual_dev->useProtocol == US_SC_DEVICE) ?
+			idesc->bInterfaceSubClass :
+			unusual_dev->useProtocol;
+	us->protocol = (unusual_dev->useTransport == US_PR_DEVICE) ?
+			idesc->bInterfaceProtocol :
+			unusual_dev->useTransport;
+	us->flags = unusual_dev->flags;
+
+	/*
+	 * This flag is only needed when we're in high-speed, so let's
+	 * disable it if we're in full-speed
+	 */
+	if (dev->speed != USB_SPEED_HIGH)
+		us->flags &= ~US_FL_GO_SLOW;
+
+	/* Log a message if a non-generic unusual_dev entry contains an
+	 * unnecessary subclass or protocol override.  This may stimulate
+	 * reports from users that will help us remove unneeded entries
+	 * from the unusual_devs.h table.
+	 */
+	if (id->idVendor || id->idProduct) {
+		static char *msgs[3] = {
+			"an unneeded SubClass entry",
+			"an unneeded Protocol entry",
+			"unneeded SubClass and Protocol entries"};
+		struct usb_device_descriptor *ddesc = &dev->descriptor;
+		int msg = -1;
+
+		if (unusual_dev->useProtocol != US_SC_DEVICE &&
+			us->subclass == idesc->bInterfaceSubClass)
+			msg += 1;
+		if (unusual_dev->useTransport != US_PR_DEVICE &&
+			us->protocol == idesc->bInterfaceProtocol)
+			msg += 2;
+		if (msg >= 0 && !(unusual_dev->flags & US_FL_NEED_OVERRIDE))
+			printk(KERN_NOTICE USB_STORAGE "This device "
+				"(%04x,%04x,%04x S %02x P %02x)"
+				" has %s in unusual_devs.h\n"
+				"   Please send a copy of this message to "
+				"<linux-usb-devel@lists.sourceforge.net>\n",
+				le16_to_cpu(ddesc->idVendor),
+				le16_to_cpu(ddesc->idProduct),
+				le16_to_cpu(ddesc->bcdDevice),
+				idesc->bInterfaceSubClass,
+				idesc->bInterfaceProtocol,
+				msgs[msg]);
+	}
+}
+
+/* Get the transport settings */
+static int get_transport(struct us_data *us)
+{
+	switch (us->protocol) {
+	case US_PR_CB:
+		us->transport_name = "Control/Bulk";
+		us->transport = usb_stor_CB_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 7;
+		break;
+
+	case US_PR_CBI:
+		us->transport_name = "Control/Bulk/Interrupt";
+		us->transport = usb_stor_CBI_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 7;
+		break;
+
+	case US_PR_BULK:
+		us->transport_name = "Bulk";
+		us->transport = usb_stor_Bulk_transport;
+		us->transport_reset = usb_stor_Bulk_reset;
+		break;
+
+#ifdef CONFIG_USB_STORAGE_USBAT
+	case US_PR_SCM_ATAPI:
+		us->transport_name = "SCM/ATAPI";
+		us->transport = usbat_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 1;
+		break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+	case US_PR_EUSB_SDDR09:
+		us->transport_name = "EUSB/SDDR09";
+		us->transport = sddr09_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 0;
+		break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_SDDR55
+	case US_PR_SDDR55:
+		us->transport_name = "SDDR55";
+		us->transport = sddr55_transport;
+		us->transport_reset = sddr55_reset;
+		us->max_lun = 0;
+		break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DPCM
+	case US_PR_DPCM_USB:
+		us->transport_name = "Control/Bulk-EUSB/SDDR09";
+		us->transport = dpcm_transport;
+		us->transport_reset = usb_stor_CB_reset;
+		us->max_lun = 1;
+		break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_FREECOM
+	case US_PR_FREECOM:
+		us->transport_name = "Freecom";
+		us->transport = freecom_transport;
+		us->transport_reset = usb_stor_freecom_reset;
+		us->max_lun = 0;
+		break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+	case US_PR_DATAFAB:
+		us->transport_name  = "Datafab Bulk-Only";
+		us->transport = datafab_transport;
+		us->transport_reset = usb_stor_Bulk_reset;
+		us->max_lun = 1;
+		break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+	case US_PR_JUMPSHOT:
+		us->transport_name  = "Lexar Jumpshot Control/Bulk";
+		us->transport = jumpshot_transport;
+		us->transport_reset = usb_stor_Bulk_reset;
+		us->max_lun = 1;
+		break;
+#endif
+
+	default:
+		return -EIO;
+	}
+	US_DEBUGP("Transport: %s\n", us->transport_name);
+
+	/* fix for single-lun devices */
+	if (us->flags & US_FL_SINGLE_LUN)
+		us->max_lun = 0;
+	return 0;
+}
+
+/* Get the protocol settings */
+static int get_protocol(struct us_data *us)
+{
+	switch (us->subclass) {
+	case US_SC_RBC:
+		us->protocol_name = "Reduced Block Commands (RBC)";
+		us->proto_handler = usb_stor_transparent_scsi_command;
+		break;
+
+	case US_SC_8020:
+		us->protocol_name = "8020i";
+		us->proto_handler = usb_stor_ATAPI_command;
+		us->max_lun = 0;
+		break;
+
+	case US_SC_QIC:
+		us->protocol_name = "QIC-157";
+		us->proto_handler = usb_stor_qic157_command;
+		us->max_lun = 0;
+		break;
+
+	case US_SC_8070:
+		us->protocol_name = "8070i";
+		us->proto_handler = usb_stor_ATAPI_command;
+		us->max_lun = 0;
+		break;
+
+	case US_SC_SCSI:
+		us->protocol_name = "Transparent SCSI";
+		us->proto_handler = usb_stor_transparent_scsi_command;
+		break;
+
+	case US_SC_UFI:
+		us->protocol_name = "Uniform Floppy Interface (UFI)";
+		us->proto_handler = usb_stor_ufi_command;
+		break;
+
+#ifdef CONFIG_USB_STORAGE_ISD200
+	case US_SC_ISD200:
+		us->protocol_name = "ISD200 ATA/ATAPI";
+		us->proto_handler = isd200_ata_command;
+		break;
+#endif
+
+	default:
+		return -EIO;
+	}
+	US_DEBUGP("Protocol: %s\n", us->protocol_name);
+	return 0;
+}
+
+/* Get the pipe settings */
+static int get_pipes(struct us_data *us)
+{
+	struct usb_host_interface *altsetting =
+		us->pusb_intf->cur_altsetting;
+	int i;
+	struct usb_endpoint_descriptor *ep;
+	struct usb_endpoint_descriptor *ep_in = NULL;
+	struct usb_endpoint_descriptor *ep_out = NULL;
+	struct usb_endpoint_descriptor *ep_int = NULL;
+
+	/*
+	 * Find the endpoints we need.
+	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
+	 * An optional interrupt is OK (necessary for CBI protocol).
+	 * We will ignore any others.
+	 */
+	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
+		ep = &altsetting->endpoint[i].desc;
+
+		/* Is it a BULK endpoint? */
+		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+				== USB_ENDPOINT_XFER_BULK) {
+			/* BULK in or out? */
+			if (ep->bEndpointAddress & USB_DIR_IN)
+				ep_in = ep;
+			else
+				ep_out = ep;
+		}
+
+		/* Is it an interrupt endpoint? */
+		else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+				== USB_ENDPOINT_XFER_INT) {
+			ep_int = ep;
+		}
+	}
+
+	if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) {
+		US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
+		return -EIO;
+	}
+
+	/* Calculate and store the pipe values */
+	us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
+	us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
+	us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
+		ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, 
+		ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+	if (ep_int) {
+		us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
+			ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+		us->ep_bInterval = ep_int->bInterval;
+	}
+	return 0;
+}
+
+/* Initialize all the dynamic resources we need */
+static int usb_stor_acquire_resources(struct us_data *us)
+{
+	int p;
+
+	us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!us->current_urb) {
+		US_DEBUGP("URB allocation failed\n");
+		return -ENOMEM;
+	}
+
+	/* Lock the device while we carry out the next two operations */
+	down(&us->dev_semaphore);
+
+	/* For bulk-only devices, determine the max LUN value */
+	if (us->protocol == US_PR_BULK) {
+		p = usb_stor_Bulk_max_lun(us);
+		if (p < 0) {
+			up(&us->dev_semaphore);
+			return p;
+		}
+		us->max_lun = p;
+	}
+
+	/* Just before we start our control thread, initialize
+	 * the device if it needs initialization */
+	if (us->unusual_dev->initFunction)
+		us->unusual_dev->initFunction(us);
+
+	up(&us->dev_semaphore);
+
+	/* Start up our control thread */
+	p = kernel_thread(usb_stor_control_thread, us, CLONE_VM);
+	if (p < 0) {
+		printk(KERN_WARNING USB_STORAGE 
+		       "Unable to start control thread\n");
+		return p;
+	}
+	us->pid = p;
+	atomic_inc(&total_threads);
+
+	/* Wait for the thread to start */
+	wait_for_completion(&(us->notify));
+
+	return 0;
+}
+
+/* Release all our dynamic resources */
+static void usb_stor_release_resources(struct us_data *us)
+{
+	US_DEBUGP("-- %s\n", __FUNCTION__);
+
+	/* Tell the control thread to exit.  The SCSI host must
+	 * already have been removed so it won't try to queue
+	 * any more commands.
+	 */
+	US_DEBUGP("-- sending exit command to thread\n");
+	up(&us->sema);
+
+	/* Call the destructor routine, if it exists */
+	if (us->extra_destructor) {
+		US_DEBUGP("-- calling extra_destructor()\n");
+		us->extra_destructor(us->extra);
+	}
+
+	/* Free the extra data and the URB */
+	kfree(us->extra);
+	usb_free_urb(us->current_urb);
+}
+
+/* Dissociate from the USB device */
+static void dissociate_dev(struct us_data *us)
+{
+	US_DEBUGP("-- %s\n", __FUNCTION__);
+
+	/* Free the device-related DMA-mapped buffers */
+	if (us->cr)
+		usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
+				us->cr_dma);
+	if (us->iobuf)
+		usb_buffer_free(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
+				us->iobuf_dma);
+
+	/* Remove our private data from the interface */
+	usb_set_intfdata(us->pusb_intf, NULL);
+}
+
+/* Thread to carry out delayed SCSI-device scanning */
+static int usb_stor_scan_thread(void * __us)
+{
+	struct us_data *us = (struct us_data *)__us;
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources.
+	 */
+	lock_kernel();
+	daemonize("usb-stor-scan");
+	unlock_kernel();
+
+	/* Acquire a reference to the host, so it won't be deallocated
+	 * until we're ready to exit */
+	scsi_host_get(us_to_host(us));
+
+	/* Signal that we've started the thread */
+	complete(&(us->notify));
+
+	printk(KERN_DEBUG
+		"usb-storage: device found at %d\n", us->pusb_dev->devnum);
+
+	/* Wait for the timeout to expire or for a disconnect */
+	if (delay_use > 0) {
+		printk(KERN_DEBUG "usb-storage: waiting for device "
+				"to settle before scanning\n");
+retry:
+		wait_event_interruptible_timeout(us->delay_wait,
+				test_bit(US_FLIDX_DISCONNECTING, &us->flags),
+				delay_use * HZ);
+		if (current->flags & PF_FREEZE) {
+			refrigerator(PF_FREEZE);
+			goto retry;
+		}
+	}
+
+	/* If the device is still connected, perform the scanning */
+	if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+		scsi_scan_host(us_to_host(us));
+		printk(KERN_DEBUG "usb-storage: device scan complete\n");
+
+		/* Should we unbind if no devices were detected? */
+	}
+
+	scsi_host_put(us_to_host(us));
+	complete_and_exit(&threads_gone, 0);
+}
+
+
+/* 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)
+{
+	struct Scsi_Host *host;
+	struct us_data *us;
+	const int id_index = id - storage_usb_ids; 
+	int result;
+
+	US_DEBUGP("USB Mass Storage device detected\n");
+
+	/*
+	 * Ask the SCSI layer to allocate a host structure, with extra
+	 * space at the end for our private us_data structure.
+	 */
+	host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
+	if (!host) {
+		printk(KERN_WARNING USB_STORAGE
+			"Unable to allocate the scsi host\n");
+		return -ENOMEM;
+	}
+
+	us = host_to_us(host);
+	memset(us, 0, sizeof(struct us_data));
+	init_MUTEX(&(us->dev_semaphore));
+	init_MUTEX_LOCKED(&(us->sema));
+	init_completion(&(us->notify));
+	init_waitqueue_head(&us->delay_wait);
+
+	/* Associate the us_data structure with the USB device */
+	result = associate_dev(us, 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.
+	 */
+	get_device_info(us, id_index);
+
+#ifdef CONFIG_USB_STORAGE_SDDR09
+	if (us->protocol == US_PR_EUSB_SDDR09 ||
+			us->protocol == US_PR_DPCM_USB) {
+		/* set the configuration -- STALL is an acceptable response here */
+		if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) {
+			US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev
+				->actconfig->desc.bConfigurationValue);
+			goto BadDevice;
+		}
+		result = usb_reset_configuration(us->pusb_dev);
+
+		US_DEBUGP("Result of usb_reset_configuration is %d\n", result);
+		if (result == -EPIPE) {
+			US_DEBUGP("-- stall on control interface\n");
+		} else if (result != 0) {
+			/* it's not a stall, but another error -- time to bail */
+			US_DEBUGP("-- Unknown error.  Rejecting device\n");
+			goto BadDevice;
+		}
+	}
+#endif
+
+	/* Get the transport, protocol, and pipe settings */
+	result = get_transport(us);
+	if (result)
+		goto BadDevice;
+	result = get_protocol(us);
+	if (result)
+		goto BadDevice;
+	result = get_pipes(us);
+	if (result)
+		goto BadDevice;
+
+	/* Acquire all the other resources and add the host */
+	result = usb_stor_acquire_resources(us);
+	if (result)
+		goto BadDevice;
+	result = scsi_add_host(host, &intf->dev);
+	if (result) {
+		printk(KERN_WARNING USB_STORAGE
+			"Unable to add the scsi host\n");
+		goto BadDevice;
+	}
+
+	/* Start up the thread for delayed SCSI-device scanning */
+	result = kernel_thread(usb_stor_scan_thread, us, CLONE_VM);
+	if (result < 0) {
+		printk(KERN_WARNING USB_STORAGE 
+		       "Unable to start the device-scanning thread\n");
+		scsi_remove_host(host);
+		goto BadDevice;
+	}
+	atomic_inc(&total_threads);
+
+	/* Wait for the thread to start */
+	wait_for_completion(&(us->notify));
+
+	return 0;
+
+	/* We come here if there are any problems */
+BadDevice:
+	US_DEBUGP("storage_probe() failed\n");
+	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
+	usb_stor_release_resources(us);
+	dissociate_dev(us);
+	scsi_host_put(host);
+	return result;
+}
+
+/* Handle a disconnect event from the USB core */
+static void storage_disconnect(struct usb_interface *intf)
+{
+	struct us_data *us = usb_get_intfdata(intf);
+
+	US_DEBUGP("storage_disconnect() called\n");
+
+	/* Prevent new USB transfers, stop the current command, and
+	 * interrupt a SCSI-scan or device-reset delay */
+	set_bit(US_FLIDX_DISCONNECTING, &us->flags);
+	usb_stor_stop_transport(us);
+	wake_up(&us->delay_wait);
+
+	/* It doesn't matter if the SCSI-scanning thread is still running.
+	 * The thread will exit when it sees the DISCONNECTING flag. */
+
+	/* Wait for the current command to finish, then remove the host */
+	down(&us->dev_semaphore);
+	up(&us->dev_semaphore);
+	scsi_remove_host(us_to_host(us));
+
+	/* Wait for everything to become idle and release all our resources */
+	usb_stor_release_resources(us);
+	dissociate_dev(us);
+
+	/* Drop our reference to the host; the SCSI core will free it
+	 * (and "us" along with it) when the refcount becomes 0. */
+	scsi_host_put(us_to_host(us));
+}
+
+/***********************************************************************
+ * Initialization and registration
+ ***********************************************************************/
+
+static int __init usb_stor_init(void)
+{
+	int retval;
+	printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
+
+	/* register the driver, return usb_register return code if error */
+	retval = usb_register(&usb_storage_driver);
+	if (retval == 0)
+		printk(KERN_INFO "USB Mass Storage support registered.\n");
+
+	return retval;
+}
+
+static void __exit usb_stor_exit(void)
+{
+	US_DEBUGP("usb_stor_exit() called\n");
+
+	/* Deregister the driver
+	 * This will cause disconnect() to be called for each
+	 * attached unit
+	 */
+	US_DEBUGP("-- calling usb_deregister()\n");
+	usb_deregister(&usb_storage_driver) ;
+
+	/* Don't return until all of our control and scanning threads
+	 * have exited.  Since each thread signals threads_gone as its
+	 * last act, we have to call wait_for_completion the right number
+	 * of times.
+	 */
+	while (atomic_read(&total_threads) > 0) {
+		wait_for_completion(&threads_gone);
+		atomic_dec(&total_threads);
+	}
+}
+
+module_init(usb_stor_init);
+module_exit(usb_stor_exit);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
new file mode 100644
index 0000000..625b7aa9
--- /dev/null
+++ b/drivers/usb/storage/usb.h
@@ -0,0 +1,204 @@
+/* Driver for USB Mass Storage compliant devices
+ * Main Header File
+ *
+ * $Id: usb.h,v 1.21 2002/04/21 02:57:59 mdharm Exp $
+ *
+ * Current development and maintenance by:
+ *   (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
+ *
+ * Initial work by:
+ *   (c) 1999 Michael Gee (michael@linuxspecific.com)
+ *
+ * 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
+ * mind when they created this document.  The commands are all very
+ * similar to commands in the SCSI-II and ATAPI specifications.
+ *
+ * It is important to note that in a number of cases this class
+ * exhibits class-specific exemptions from the USB specification.
+ * Notably the usage of NAK, STALL and ACK differs from the norm, in
+ * that they are used to communicate wait, failed and OK on commands.
+ *
+ * Also, for certain devices, the interrupt endpoint is used to convey
+ * status of a command.
+ *
+ * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more
+ * information about this driver.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#include <linux/usb.h>
+#include <linux/blkdev.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <scsi/scsi_host.h>
+
+struct us_data;
+struct scsi_cmnd;
+
+/*
+ * Unusual device list definitions 
+ */
+
+struct us_unusual_dev {
+	const char* vendorName;
+	const char* productName;
+	__u8  useProtocol;
+	__u8  useTransport;
+	int (*initFunction)(struct us_data *);
+	unsigned int flags;
+};
+
+/*
+ * Static flag definitions.  We use this roundabout technique so that the
+ * proc_info() routine can automatically display a message for each flag.
+ */
+#define US_DO_ALL_FLAGS						\
+	US_FLAG(SINGLE_LUN,	0x00000001)			\
+		/* allow access to only LUN 0 */		\
+	US_FLAG(NEED_OVERRIDE,	0x00000002)			\
+		/* unusual_devs entry is necessary */		\
+	US_FLAG(SCM_MULT_TARG,	0x00000004)			\
+		/* supports multiple targets */			\
+	US_FLAG(FIX_INQUIRY,	0x00000008)			\
+		/* INQUIRY response needs faking */		\
+	US_FLAG(FIX_CAPACITY,	0x00000010)			\
+		/* READ CAPACITY response too big */		\
+	US_FLAG(IGNORE_RESIDUE,	0x00000020)			\
+		/* reported residue is wrong */			\
+	US_FLAG(BULK32,		0x00000040)			\
+		/* Uses 32-byte CBW length */			\
+	US_FLAG(NOT_LOCKABLE,	0x00000080)			\
+		/* PREVENT/ALLOW not supported */		\
+	US_FLAG(GO_SLOW,	0x00000100)			\
+		/* Need delay after Command phase */		\
+	US_FLAG(NO_WP_DETECT,	0x00000200)			\
+		/* Don't check for write-protect */		\
+
+#define US_FLAG(name, value)	US_FL_##name = value ,
+enum { US_DO_ALL_FLAGS };
+#undef US_FLAG
+
+/* Dynamic flag definitions: used in set_bit() etc. */
+#define US_FLIDX_URB_ACTIVE	18  /* 0x00040000  current_urb is in use  */
+#define US_FLIDX_SG_ACTIVE	19  /* 0x00080000  current_sg is in use   */
+#define US_FLIDX_ABORTING	20  /* 0x00100000  abort is in progress   */
+#define US_FLIDX_DISCONNECTING	21  /* 0x00200000  disconnect in progress */
+#define ABORTING_OR_DISCONNECTING	((1UL << US_FLIDX_ABORTING) | \
+					 (1UL << US_FLIDX_DISCONNECTING))
+#define US_FLIDX_RESETTING	22  /* 0x00400000  device reset in progress */
+#define US_FLIDX_TIMED_OUT	23  /* 0x00800000  SCSI midlayer timed out  */
+
+
+#define USB_STOR_STRING_LEN 32
+
+/*
+ * We provide a DMA-mapped I/O buffer for use with small USB transfers.
+ * It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
+ * 31-byte buffer.  But Freecom needs a 64-byte buffer, so that's the
+ * size we'll allocate.
+ */
+
+#define US_IOBUF_SIZE		64	/* Size of the DMA-mapped I/O buffer */
+
+typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*);
+typedef int (*trans_reset)(struct us_data*);
+typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*);
+typedef void (*extra_data_destructor)(void *);	 /* extra data destructor   */
+
+/* we allocate one of these for every device that we remember */
+struct us_data {
+	/* The device we're working with
+	 * It's important to note:
+	 *    (o) you must hold dev_semaphore to change pusb_dev
+	 */
+	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
+	struct usb_device	*pusb_dev;	 /* this usb_device */
+	struct usb_interface	*pusb_intf;	 /* this interface */
+	struct us_unusual_dev   *unusual_dev;	 /* device-filter entry     */
+	unsigned long		flags;		 /* from filter initially */
+	unsigned int		send_bulk_pipe;	 /* cached pipe values */
+	unsigned int		recv_bulk_pipe;
+	unsigned int		send_ctrl_pipe;
+	unsigned int		recv_ctrl_pipe;
+	unsigned int		recv_intr_pipe;
+
+	/* information about the device */
+	char			*transport_name;
+	char			*protocol_name;
+	__le32			bcs_signature;
+	u8			subclass;
+	u8			protocol;
+	u8			max_lun;
+
+	u8			ifnum;		 /* interface number   */
+	u8			ep_bInterval;	 /* interrupt interval */ 
+
+	/* function pointers for this device */
+	trans_cmnd		transport;	 /* transport function	   */
+	trans_reset		transport_reset; /* transport device reset */
+	proto_cmnd		proto_handler;	 /* protocol handler	   */
+
+	/* SCSI interfaces */
+	struct scsi_cmnd	*srb;		 /* current srb		*/
+
+	/* thread information */
+	int			pid;		 /* control thread	 */
+
+	/* control and bulk communications data */
+	struct urb		*current_urb;	 /* USB requests	 */
+	struct usb_ctrlrequest	*cr;		 /* control requests	 */
+	struct usb_sg_request	current_sg;	 /* scatter-gather req.  */
+	unsigned char		*iobuf;		 /* I/O buffer		 */
+	dma_addr_t		cr_dma;		 /* buffer DMA addresses */
+	dma_addr_t		iobuf_dma;
+
+	/* mutual exclusion and synchronization structures */
+	struct semaphore	sema;		 /* to sleep thread on	    */
+	struct completion	notify;		 /* thread begin/end	    */
+	wait_queue_head_t	delay_wait;	 /* wait during scan, reset */
+
+	/* subdriver information */
+	void			*extra;		 /* Any extra data          */
+	extra_data_destructor	extra_destructor;/* extra data destructor   */
+};
+
+/* Convert between us_data and the corresponding Scsi_Host */
+static struct Scsi_Host inline *us_to_host(struct us_data *us) {
+	return container_of((void *) us, struct Scsi_Host, hostdata);
+}
+static struct us_data inline *host_to_us(struct Scsi_Host *host) {
+	return (struct us_data *) host->hostdata;
+}
+
+/* Function to fill an inquiry response. See usb.c for details */
+extern void fill_inquiry_response(struct us_data *us,
+	unsigned char *data, unsigned int data_len);
+
+/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
+ * single queue element srb for write access */
+#define scsi_unlock(host)	spin_unlock_irq(host->host_lock)
+#define scsi_lock(host)		spin_lock_irq(host->host_lock)
+
+
+/* Vendor ID list for devices that require special handling */
+#define USB_VENDOR_ID_GENESYS		0x05e3	/* Genesys Logic */
+
+#endif