diff -ruN linux-2.6.9.orig/drivers/usb/storage/Kconfig linux-2.6.9/drivers/usb/storage/Kconfig
--- linux-2.6.9.orig/drivers/usb/storage/Kconfig	2004-10-19 01:55:28.000000000 +0400
+++ linux-2.6.9/drivers/usb/storage/Kconfig	2004-12-17 23:29:07.000000000 +0300
@@ -111,3 +111,8 @@
 	  Say Y here to include additional code to support the Lexar Jumpshot
 	  USB CompactFlash reader.
 
+config USB_STORAGE_USS725
+	bool "USS725 chipset support (EXPERIMENTAL)"
+	depends on USB_STORAGE && EXPERIMENTAL
+	help
+	  Say Y here to include additional code to support the USS725 chipset.
diff -ruN linux-2.6.9.orig/drivers/usb/storage/Makefile linux-2.6.9/drivers/usb/storage/Makefile
--- linux-2.6.9.orig/drivers/usb/storage/Makefile	2004-10-19 01:54:38.000000000 +0400
+++ linux-2.6.9/drivers/usb/storage/Makefile	2004-12-17 23:29:07.000000000 +0300
@@ -18,6 +18,7 @@
 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-obj-$(CONFIG_USB_STORAGE_USS725)	+= uss725.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
diff -ruN linux-2.6.9.orig/drivers/usb/storage/transport.h linux-2.6.9/drivers/usb/storage/transport.h
--- linux-2.6.9.orig/drivers/usb/storage/transport.h	2004-10-19 01:53:51.000000000 +0400
+++ linux-2.6.9/drivers/usb/storage/transport.h	2004-12-17 23:29:07.000000000 +0300
@@ -75,6 +75,10 @@
 #define US_PR_JUMPSHOT  0xf3		/* Lexar Jumpshot */
 #endif
 
+#ifdef CONFIG_USB_STORAGE_USS725
+#define US_PR_USS725    0xf4		/* USS725 chipset */
+#endif
+
 #define US_PR_DEVICE	0xff		/* Use device's value */
 
 /*
diff -ruN linux-2.6.9.orig/drivers/usb/storage/unusual_devs.h linux-2.6.9/drivers/usb/storage/unusual_devs.h
--- linux-2.6.9.orig/drivers/usb/storage/unusual_devs.h	2004-12-17 23:26:46.000000000 +0300
+++ linux-2.6.9/drivers/usb/storage/unusual_devs.h	2004-12-17 23:29:07.000000000 +0300
@@ -421,6 +421,25 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
+#ifdef CONFIG_USB_STORAGE_USS725
+UNUSUAL_DEV(  0x05ab, 0x0200, 0x0100, 0x0110,
+                "In-System",
+                "USS-725 USB/IDE Bridge (ATA/ATAPI)",
+                US_SC_SCSI, US_PR_USS725, uss725_init, 0 ),
+
+/* Reported by <dwiebold@cactus.org> for original Pockey */
+UNUSUAL_DEV(  0x05ab, 0x0202, 0x0100, 0x0155,
+                "In-System",
+                "USS-725 USB/IDE Bridge (ATA/ATAPI)",
+                US_SC_SCSI, US_PR_USS725, uss725_init, 0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x0581, 0x0100, 0x0110,
+                "In-System",
+                "USS-725 USB/IDE Bridge (ATA/ATAPI)",
+                US_SC_SCSI, US_PR_USS725, uss725_init, 0 ),
+#endif
+
+
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 UNUSUAL_DEV(  0x05dc, 0x0001, 0x0000, 0x0001,
 		"Lexar",
diff -ruN linux-2.6.9.orig/drivers/usb/storage/usb.c linux-2.6.9/drivers/usb/storage/usb.c
--- linux-2.6.9.orig/drivers/usb/storage/usb.c	2004-12-17 23:26:46.000000000 +0300
+++ linux-2.6.9/drivers/usb/storage/usb.c	2004-12-17 23:29:07.000000000 +0300
@@ -86,6 +86,9 @@
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 #include "jumpshot.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_USS725
+#include "uss725.h"
+#endif
 
 
 #include <linux/module.h>
@@ -630,6 +633,15 @@
 		break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_USS725
+	case US_PR_USS725:
+		us->transport_name  = "USS725 Control/Bulk";
+		us->transport = uss725_transport;
+		us->transport_reset = uss725_reset;
+		us->max_lun = 0;
+		break;
+#endif
+
 	default:
 		return -EIO;
 	}
@@ -940,6 +952,15 @@
 	}
 #endif
 
+#ifdef CONFIG_USB_STORAGE_USS725
+	if (us->protocol == US_PR_USS725) {
+		if (usb_set_interface(us->pusb_dev, 0, 2 )) {
+			US_DEBUGP("USS725: Failed to setting interface\n");
+			goto BadDevice;
+		}
+	}
+#endif
+
 	/* Get the transport, protocol, and pipe settings */
 	result = get_transport(us);
 	if (result)
diff -ruN linux-2.6.9.orig/drivers/usb/storage/uss725.c linux-2.6.9/drivers/usb/storage/uss725.c
--- linux-2.6.9.orig/drivers/usb/storage/uss725.c	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.9/drivers/usb/storage/uss725.c	2004-12-17 23:22:52.000000000 +0300
@@ -0,0 +1,2164 @@
+/* Storage driver for In-System Design, Inc. USS-725
+ *
+ * Current development and maintenance:
+ *   (C) 2002 Nicolas Planel (nplanel@mandrakesoft.com)
+ *
+ * The USS-725 was really made for adapting parallell printers to USB, but
+ * using a fancy code sequencer trick ISD was able to use it for storage
+ * applications too. The downside is that the driver becomes very complex.
+ *
+ *
+ * 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-11-12: v0.1 First usable version based on ISD200 and 
+ *              first work of Björn Stenberg <bjorn@haxx.se>. 
+ *              (support only one ATA device)
+ *              (nplanel@mandrakesoft.com)
+ *
+ *  2002-11-27: v0.11 Fix ghost device (nplanel@mandrakesoft.com)
+ *
+ *  2003-01-14: Correcting master-slave IDE devices detection 
+ *              and bugs in function uss725_data_seq(), 
+ *              which resulted in freezing kernel at reading 
+ *              and writing data on USB device.
+ *              Igor Mokrushin <mcmcc@mail.ru>
+ *
+ *  2003-02-11: v0.12 Thanks to Igor for his patch 
+ *              Improve data transfert rate (read-only)
+ *
+ *  2003-04-30: v0.12.1 New function: Check Master/Slave/CS(Cable Select) 
+ *              IDE devices detection status. 
+ *              Fix detect mode device for ZIV1 (http://www.ziv.ru) 
+ *              and other USB HDD device.
+ *              Igor Mokrushin <mcmcc@mail.ru>
+ * 
+ */
+
+/* Include files */
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "scsiglue.h"
+#include "scsi.h"
+#include "uss725.h"
+#include "uss725_regs.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/completion.h>
+
+#define BSY_TIMEOUT 10
+#define SEQ_TIMEOUT 5
+
+#define ATA_BYTES_PER_BLOCK 512
+
+/* Timeout defines (in Seconds) */
+#define USS725_ENUM_BSY_TIMEOUT         35
+#define USS725_ENUM_DETECT_TIMEOUT      30
+#define USS725_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
+
+//
+// ATAPI State Machine constants
+//
+#define ATAPI_STATE_COMMAND_START		0x00
+#define ATAPI_STATE_DEVICE_BUSY			0x01
+#define ATAPI_STATE_CHECK_CYLHILO 		0x02
+#define ATAPI_STATE_DATA_OPTIMIZED		0x03
+#define ATAPI_STATE_DATA_LOOP_ON_DRQ		0x04
+#define ATAPI_STATE_DATA_NOT_FINISHED		0x05
+#define ATAPI_STATE_DO_CYLHILO			0x06
+#define ATAPI_STATE_COMPLETE_TIMEOUT 		0x07
+#define ATAPI_STATE_CHECK_COMMAND_COMPLETE	0x08
+#define ATAPI_STATE_DEVICE_ERROR		0xFD
+#define ATAPI_STATE_RESET_ERROR			0xFE
+#define ATAPI_STATE_COMMAND_COMPLETE	 	0xFF
+
+/* command_setX bit definitions */
+#define COMMANDSET_REMOVABLE	0x02
+#define COMMANDSET_MEDIA_STATUS 0x10
+
+//
+// ATAPI commands
+//
+#define ATAPI_COMMAND_MODE_SENSE            0x5A
+#define ATAPI_COMMAND_MODE_SELECT           0x55
+#define ATAPI_COMMAND_FORMAT_UNIT           0x24
+#define ATAPI_COMMAND_PACKET                0xA0
+#define ATAPI_COMMAND_IDENTIFY              0xA1
+
+//
+// IDE constants
+//
+#define ATA_ADDRESS_ALT_STATUS  0x0e
+#define ATA_ADDRESS_COMMAND     0x17
+#define ATA_ADDRESS_CYL_HIGH    0x15
+#define ATA_ADDRESS_CYL_LOW     0x14
+#define ATA_ADDRESS_DATA        0x10
+#define ATA_ADDRESS_DEV_HEAD    0x16
+#define ATA_ADDRESS_DEV_CNTRL   0x0e
+#define ATA_ADDRESS_ERROR       0x11
+#define ATA_ADDRESS_FEATURES    0x11
+#define ATA_ADDRESS_SECT_CNT    0x12
+#define ATA_ADDRESS_SECT_NUM    0x13
+#define ATA_ADDRESS_STATUS      0x17
+
+//
+// ATA_ADDRESS_STATUS (and ATA_ADDRESS_ALT_STATUS) definition
+//
+#define ATA_STATUS_ERROR             0x01
+#define ATA_STATUS_INDEX             0x02
+#define ATA_STATUS_CORRECTED_ERROR   0x04
+#define ATA_STATUS_DRQ               0x08
+#define ATA_STATUS_DSC               0x10
+#define ATA_STATUS_DEVICE_FAULT      0x20
+#define ATA_STATUS_DRDY              0x40
+#define ATA_STATUS_IDLE              0x50
+#define ATA_STATUS_BUSY              0x80
+
+
+//
+// ATA return state constants
+//
+#define ATA_STATE_SUCCESS			0x00
+#define ATA_STATE_RESUBMIT			0x01
+#define ATA_STATE_TIMEOUT			0x02
+#define ATA_STATE_INVALID_REQUEST		0xFD
+#define ATA_STATE_DEVICE_ERROR		 	0xFE
+#define ATA_STATE_RESET_ERROR			0xFF
+
+//
+// ATA_ADDRESS_DEV_HEAD definition
+//
+#define ATA_ADDRESS_DEVHEAD_STD         0xa0 // on-bits required for all head-reg writes
+#define ATA_ADDRESS_DEVHEAD_LBA_MODE    0x40    
+#define ATA_ADDRESS_DEVHEAD_SLAVE       0x10
+
+//
+// WAIT return state constants
+//
+#define WAIT_STATE_SUCCESS			0x00
+#define WAIT_STATE_BUSY				0x01
+#define WAIT_STATE_TIMEOUT_ERROR		0xFC
+#define WAIT_STATE_DEVICE_DRQ 			0xFD
+#define WAIT_STATE_DEVICE_ERROR		 	0xFE
+#define WAIT_STATE_RESET_ERROR			0xFF
+
+#define ATA_REGMASK_FEATURES 			0x01
+#define ATA_REGMASK_SECTOR_COUNT 		0x02
+#define ATA_REGMASK_SECTOR_NUM 			0x04
+#define ATA_REGMASK_CYLINDER 			0x08
+#define ATA_REGMASK_HEAD			0x10
+
+#define ATA_CMDMASK_NO_CHECK_FOR_BSY_AND_ERR_AFTER_CMD 	0x01
+#define ATA_CMDMASK_CHECK_FOR_DRQ_AFTER_CMD 		0x02
+#define ATA_CMDMASK_WILL_XFER_DATA			0x04
+
+/* ATA drive control definitions */
+#define ATA_DC_DISABLE_INTERRUPTS    0x02
+#define ATA_DC_RESET_CONTROLLER      0x04
+#define ATA_DC_REENABLE_CONTROLLER   0x00
+
+// CDB operation codes not normally defined
+#define SCSIOP_WRITECONTINUE       0xE1
+
+// IDE master and slave device defined
+#define IDE_MASTER		   ATA_ADDRESS_DEVHEAD_STD
+#define IDE_SLAVE                  ATA_ADDRESS_DEVHEAD_STD|ATA_ADDRESS_DEVHEAD_SLAVE
+
+/*
+ * Inquiry data structure. This is the data returned from the target
+ * after it receives an 'INQUIRY' SCSI command .
+ *
+ * This structure may be extended by the number of bytes specified
+ * in the field AdditionalLength. The defined size constant only
+ * includes fields through ProductRevisionLevel.
+ */
+
+#define INQUIRY_SIZE 36
+#define sg_address(psg)		(page_address((psg).page) + (psg).offset)
+
+struct inquiry_data {
+	unsigned char DeviceType : 5;
+	unsigned char DeviceTypeQualifier : 3;
+	unsigned char DeviceTypeModifier : 7;
+	unsigned char RemovableMedia : 1;
+	unsigned char Versions;
+	unsigned char ResponseDataFormat : 4;
+	unsigned char HiSupport : 1;
+	unsigned char NormACA : 1;
+	unsigned char ReservedBit : 1;
+	unsigned char AERC : 1;
+	unsigned char AdditionalLength;
+	unsigned char Reserved[2];
+	unsigned char SoftReset : 1;
+	unsigned char CommandQueue : 1;
+	unsigned char Reserved2 : 1;
+	unsigned char LinkedCommands : 1;
+	unsigned char Synchronous : 1;
+	unsigned char Wide16Bit : 1;
+	unsigned char Wide32Bit : 1;
+	unsigned char RelativeAddressing : 1;
+	unsigned char VendorId[8];
+	unsigned char ProductId[16];
+	unsigned char ProductRevisionLevel[4];
+	unsigned char VendorSpecific[20];
+	unsigned char Reserved3[40];
+} __attribute__ ((packed));
+
+struct ata_regs {
+	int regFlags;
+	int cmdFlags;
+
+	int features;
+	int sectorCount;
+	int sectorNum;
+	int cylinder;
+	int head;
+	int cmd;
+};
+
+/*
+ * Read Capacity Data - returned in Big Endian format
+ */
+
+struct read_capacity_data {
+        unsigned long LogicalBlockAddress;
+        unsigned long BytesPerBlock;
+};
+
+struct uss725_info {
+	struct inquiry_data InquiryData;
+	struct hd_driveid drive;
+ 	unsigned char ATARegs[8];
+	unsigned char DeviceHead;
+	unsigned char DeviceFlags;
+
+	char * xfer_buffer;
+        unsigned int xfer_len_buffer;
+	int xfer_pipe;
+
+	struct completion notify;
+	int exit_code;
+	/* maximum number of LUNs supported */
+	unsigned char MaxLUNs;
+};
+
+/*
+ *  General purpose return codes
+ */ 
+
+#define USS725_ERROR                -1
+#define USS725_GOOD                 0
+
+/*
+ * Transport return codes
+ */
+
+#define USS725_TRANSPORT_GOOD       USB_STOR_TRANSPORT_GOOD        /* Transport good, command good     */
+#define USS725_TRANSPORT_FAILED     USB_STOR_TRANSPORT_FAILED      /* Transport good, command failed   */
+#define USS725_TRANSPORT_ERROR      USB_STOR_TRANSPORT_ERROR       /* Transport bad (i.e. device dead) */
+#define USS725_TRANSPORT_SHORT      USB_STOR_TRANSPORT_ERROR+1     /* Transport short transfert        */
+
+/* driver action codes */
+enum {	ACTION_READ_STATUS=0,
+	ACTION_RESET,		
+	ACTION_REENABLE,		
+	ACTION_SOFT_RESET,	
+	ACTION_ENUM,		
+	ACTION_IDENTIFY };
+
+/*
+ * DeviceType field
+ */
+#define DIRECT_ACCESS_DEVICE    0x00    /* disks */
+
+/*
+ * 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
+
+
+/***********************************************************************
+ * USS725 specific routines
+ ***********************************************************************/
+
+int uss725_send_seq(struct us_data* us, unsigned char* seq, int len);
+
+/**************************************************************************
+ * uss725_get_seq_status
+ *
+ * Get sequencer status
+ */
+int uss725_get_seq_status( struct us_data* us, struct seqstatus* status )
+{
+	int rc;
+	status->seqPos = 0xff;
+	rc = usb_control_msg(us->pusb_dev,
+			     usb_rcvctrlpipe(us->pusb_dev,0),
+			     GET_SEQ_STATUS,
+			     USB_DIR_IN | USB_TYPE_VENDOR,
+			     0,
+			     0,
+			     status,
+			     sizeof(struct seqstatus),3*HZ);
+	if ( rc >= 0 ) 
+		return USS725_GOOD;
+
+	US_DEBUGP("uss725 seq status failed! (%d)\n",rc);
+	return USS725_ERROR;
+}
+
+/**************************************************************************
+ * uss725_abort_seq
+ *
+ * Get sequencer status
+ */
+int uss725_abort_seq( struct us_data* us )
+{
+	int rc;
+	rc = usb_control_msg(us->pusb_dev,
+			     usb_sndctrlpipe(us->pusb_dev,0),
+			     SEQ_ABORT,
+			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			     0, 0, NULL, 0, HZ);
+	if ( rc >= 0 ) 
+		return USS725_GOOD;
+
+	US_DEBUGP("uss725 abort seq failed! (%d)\n",rc);
+	return USS725_ERROR;
+}
+
+int uss725_seq_reset_regs(struct us_data* us) {
+	unsigned char seq_reset_regs[] =
+	{
+		0x00,0x00,SEQ_BLOCKING_BIT, 			// Loop Count (WORD) & Block bit (bit 8 of BYTE)
+		(SEQ_RRMW|REG_SETU), REG_SETU_CLEAR_BULK_OUT, REG_SETU_CLEAR_BULK_OUT,
+		(SEQ_RRMW|REG_SETU), REG_SETU_HOLD_BULK, REG_SETU_HOLD_BULK,
+		(SEQ_RRMW|REG_CCTR), REG_CCTR_MANUAL_REVERSE, REG_CCTR_MANUAL_REVERSE,
+	};
+	
+	US_DEBUGP("uss725 seq_reset_regs: reset!\n");
+	if(uss725_send_seq(us, seq_reset_regs, sizeof(seq_reset_regs)) != USS725_GOOD) {
+		US_DEBUGP("uss725 seq_reset_regs: reset failed!\n");
+		return USS725_ERROR;
+	}
+	return USS725_GOOD;
+}
+
+#ifdef CONFIG_USB_STORAGE_DEBUG
+void print_seqstatus(struct us_data* us, struct seqstatus status) {
+	US_DEBUGP("seqPos: %d\n",status.seqPos);
+	US_DEBUGP("globalLoopCount: %d\n", status.globalLoopCountHigh <<8 |
+		  status.globalLoopCountLow);
+	US_DEBUGP("status_active: %d\n",status.statusFlags);
+	US_DEBUGP("instructLoopCount: %d\n",(status.statusFlags & 0x0f)<<16 | 
+		  status.instructLoopCountMid<<8 |
+		  status.instructLoopCountLow );
+}
+
+void regName(char reg, char * name) {
+	switch(reg & 0x0f) {
+	case REG_DATA:
+		strcpy(name, "REG_DATA");
+		break;
+	case REG_STAT:
+		strcpy(name, "REG_STAT");
+		break;
+	case REG_CTRL:
+		strcpy(name, "REG_CTRL");
+		break;
+	case REG_EPPA:
+		strcpy(name, "REG_EPPA");
+		break;
+	case REG_EPPD:
+		strcpy(name, "REG_EPPD");
+		break;
+	case REG_ECPA:
+		strcpy(name, "REG_ECPA");
+		break;
+	case REG_ECRR:
+		strcpy(name, "REG_ECRR");
+		break;
+	case REG_CCTR:
+		strcpy(name, "REG_CCTR");
+		break;
+	case REG_SETU:
+		strcpy(name, "REG_SETU");
+		break;
+	case REG_TIMO:
+		strcpy(name, "REG_TIMO");
+		break;
+	case REG_ATAA:
+		strcpy(name, "REG_ATTA");
+		break;
+	default:
+		sprintf(name,"0x%02x",reg);
+		break;
+	}
+}
+
+void uss725_debug_seq(char * s, int len, int pos) {
+	int i=0;
+	char reg_name[10];
+
+	do {
+		if(i==pos) 
+			US_DEBUGP("==> ");
+		else
+			US_DEBUGP("    ");
+		
+		regName(s[i], reg_name);
+		switch (s[i] & 0xf0) {
+		case SEQ_RRMW:
+			US_DEBUGP("(SEQ_RRMW|%s), 0x%02x, 0x%02x,\n",reg_name,(s[i+1]),(s[i+2]));
+			i+=3;
+			break;
+		case SEQ_RRCM:
+			US_DEBUGP("(SEQ_RRCM|%s), 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",reg_name,s[i+1],s[i+2],s[i+3],s[i+4]);
+			i+=5;
+			break;
+		case SEQ_RWRI:
+			US_DEBUGP("(SEQ_RWRI|%s), 0x%02x,\n",reg_name,s[i+1]);
+			i+=2;
+			break;
+		case SEQ_RREN:
+			US_DEBUGP("(SEQ_RREN|0x%02x),\n",s[i] & 0x01);
+			i++;
+			break;
+		case SEQ_WBIB:
+			US_DEBUGP("(SEQ_WBIB|0x%02x), 0x%02x, 0x%02x,\n",s[i]&0x0f,s[i+1],s[i+2]);
+			i+=3;
+			break;
+		case SEQ_WBOB:
+			US_DEBUGP("(SEQ_WBOB|0x%02x), 0x%02x, 0x%02x,\n",s[i]&0x0f,s[i+1],s[i+2]);
+			i+=3;
+			break;
+		case SEQ_DATI:
+			US_DEBUGP("(SEQ_DATI|%s),\n",reg_name);
+			i++;
+			break;
+		case SEQ_DATO:
+			US_DEBUGP("(SEQ_DATO|%s),\n",reg_name);
+			i++;
+			break;
+		case SEQ_EPPI:
+			US_DEBUGP("(SEQ_EPPI|0x%02x), 0x%02x, 0x%02x,\n",s[i]&0x0f,s[i+1],s[i+2]);
+			i+=3;
+			break;
+		case SEQ_NOOP:
+			US_DEBUGP("(SEQ_NOOP|0x%02x), 0x%02x,\n",s[i]&0x0f,s[i+1]);
+			i+=2;
+			break;
+		/*case SEQ_SUBR:*/
+		case SEQ_RETN:
+			US_DEBUGP("(SEQ_SUBR|0x%02x), 0x%02x,\n",s[i]&0x0f,s[i+1]);
+			i+=2;
+			break;
+			
+		default:
+			US_DEBUGP("unknown op code :(\n");
+			return;
+		}
+	}
+	while(i<len);
+}
+#endif /* CONFIG_USB_STORAGE_DEBUG */
+
+int uss725_send_seq(struct us_data* us, unsigned char* seq, int len)
+{
+	static int recursive = 0;
+	int rc,value,index;
+	unsigned char* ptr;
+	unsigned char buf[128];
+	struct seqstatus seqStatus;
+
+	if ( recursive++ > 1) {
+		printk(KERN_CRIT "uss725 driver unusable!\n");
+		return USS725_ERROR;
+	}
+
+	if ( len < 3 ) {
+		US_DEBUGP("uss725 Bad microcode sequence! (only %d bytes long)\n",len);
+		return USS725_ERROR;
+	}
+
+	memcpy(buf,seq,len);
+	value = (seq[2] << 8) | seq[0];
+	index = seq[1];
+	ptr = buf + 3;
+
+	rc = usb_control_msg(us->pusb_dev,
+			     usb_sndctrlpipe(us->pusb_dev,0),
+			     SEQ_LOAD, 
+			     USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			     value,
+			     index,
+			     ptr,
+			     len-3, SEQ_TIMEOUT * HZ);
+	if ( rc >= 0 ) {
+		recursive = 0;
+		return USS725_GOOD;
+	}
+
+	US_DEBUGP("uss725 sequence load failed! (%d)\n",rc);
+	if(uss725_get_seq_status(us,&seqStatus) == USS725_GOOD) {
+		if (seqStatus.statusFlags & SEQSTATUSF_ACTIVE) {
+			/* abort sequencer */
+			US_DEBUGP("Aborting Sequencer\n");
+			uss725_abort_seq(us);
+		}
+#ifdef CONFIG_USB_STORAGE_DEBUG
+		print_seqstatus(us,seqStatus);
+		uss725_debug_seq(seq,len,seqStatus.seqPos);
+#endif
+		uss725_seq_reset_regs(us);
+	} else 
+		US_DEBUGP("Unable to get sequencer status\n");
+
+	return USS725_ERROR;
+}
+
+int uss725_read_ata_reg(struct us_data* us, int reg, unsigned char* buf)
+{
+	unsigned char seq_read_ata_reg[] =
+	{
+		0x00,0x00,SEQ_BLOCKING_BIT,
+		(SEQ_RRMW|REG_CCTR), REG_CCTR_MANUAL_REVERSE, REG_CCTR_MANUAL_REVERSE,
+		(SEQ_RRMW|REG_SETU), 0x00, REG_SETU_HOLD_BULK,
+		(SEQ_RWRI|REG_ATAA), reg, 
+		(SEQ_DATI|REG_EPPA), 
+		(SEQ_RRMW|REG_SETU), REG_SETU_HOLD_BULK, REG_SETU_HOLD_BULK,
+		(SEQ_RRMW|REG_CCTR), 0x00, REG_CCTR_MANUAL_REVERSE
+	};
+	unsigned int partial;
+	int rc;
+
+	/* send sequence to read a register */
+	rc = uss725_send_seq(us, seq_read_ata_reg, sizeof(seq_read_ata_reg));
+	if (rc) {
+		US_DEBUGP("uss725 ATA register read %d failed! (%d)\n",
+			  reg,rc);
+		return USS725_ERROR;
+	}
+
+	/* read resulting byte */
+	rc = usb_stor_bulk_transfer_buf(us,
+			       us->recv_bulk_pipe,
+			       buf,
+			       1, &partial);
+	if (rc) {
+		US_DEBUGP("uss725 ATA register bulk read failed! (%d)\n", rc);
+		return USS725_ERROR;
+	}
+	US_DEBUGP("uss725 seq: read ata reg %d = 0x%02x\n",reg,*buf);
+
+	return USS725_GOOD;
+}
+
+int uss725_write_ata_reg(struct us_data* us, int reg, int data)
+{
+	unsigned char seq_write_ata_reg[] =
+	{
+		/* Loop Count (WORD) & Block bit (bit 8 of BYTE) */
+		0x00,0x00,SEQ_BLOCKING_BIT, 
+		(SEQ_RWRI|REG_ATAA), reg,
+		(SEQ_RWRI|REG_EPPA), data
+	};
+	int rc;
+
+	/* send sequence to write a register */
+	US_DEBUGP("uss725 seq: write ata reg %d = 0x%02x\n",reg,data);
+	rc = uss725_send_seq(us, 
+			     seq_write_ata_reg, 
+			     sizeof(seq_write_ata_reg));
+	if (rc) {
+		US_DEBUGP("uss725 ATA register write %d = %d failed! (%d)\n",
+			  reg,data,rc);
+		return USS725_ERROR;
+	}
+
+	return USS725_GOOD;
+}
+
+/**************************************************************************
+ * uss725_wait_bsy
+ *
+ * Wait for device to not be busy
+ */
+int uss725_wait_bsy( struct us_data* us, int timeout )
+{
+	unsigned long start = jiffies;
+	int state = WAIT_STATE_BUSY;
+
+	US_DEBUGP("uss725: wait_for_bsy()\n");
+
+	while ( WAIT_STATE_BUSY == state ) {
+		int rc = USS725_ERROR;
+	
+		/* the hands-on version */
+		while ( jiffies < (start + timeout*HZ) ) {
+			unsigned char status;
+			rc = uss725_read_ata_reg(us,ATA_ADDRESS_STATUS,&status);
+			if (rc)
+				break;
+			if ( status & ATA_STATUS_BUSY ) {
+				US_DEBUGP("Device still BUSY, resubmit requested\n");
+				rc = USS725_ERROR; /* signal error if loop times out */
+				msleep(100);
+			}
+			else if ( status & ATA_STATUS_ERROR ) {
+				US_DEBUGP("Device ERROR, return device error\n");
+				state = WAIT_STATE_DEVICE_ERROR;
+				break;
+			}
+			else if ( status & ATA_STATUS_DRQ ) {
+				US_DEBUGP("Device DRQ detected\n");
+				state = WAIT_STATE_DEVICE_DRQ;
+				break;
+			}
+			else {
+				state = WAIT_STATE_SUCCESS;
+				break;
+			}
+		}
+	}
+	return state;
+}
+
+/**************************************************************************
+ * uss725_identify
+ *
+ * Attempt to process an ATA/ATAPI Identify request
+ */
+int uss725_identify( struct us_data* us, int atapi )
+{
+	/* line 1343 */
+	int buflen = sizeof(struct hd_driveid);
+	struct uss725_info *info = (struct uss725_info *)us->extra;
+
+	unsigned char seq_identify_cmd[] = {
+		0x00,0x00,SEQ_BLOCKING_BIT,
+		(SEQ_RWRI|REG_ATAA), ATA_ADDRESS_DEV_HEAD,
+		(SEQ_RWRI|REG_EPPA), ATA_ADDRESS_DEVHEAD_STD | info->DeviceHead,
+		(SEQ_RWRI|REG_ATAA), ATA_ADDRESS_ALT_STATUS,
+		(SEQ_RRCM|REG_EPPA), 0xFF, 0xFF, 0x00, ATA_STATUS_BUSY,
+		(SEQ_RWRI|REG_ATAA), ATA_ADDRESS_COMMAND,
+		(SEQ_RWRI|REG_EPPA), atapi ? WIN_PIDENTIFY : WIN_IDENTIFY
+	};
+
+	unsigned char seq_identify_move_data[] = {
+		0x00,0x00,0x00,
+		(SEQ_RRMW|REG_CCTR), 0x80,0x80,
+		(SEQ_RWRI|REG_ATAA), ATA_ADDRESS_DATA,
+		(SEQ_RRMW|REG_SETU), 0x00,0x80,
+		(SEQ_RRMW|REG_CTRL), 0x20,0x20,
+		(SEQ_WBIB|0x00), (buflen-1)>>8, buflen-1,
+		(SEQ_RRMW|REG_CTRL), 0x00,0x20,
+		(SEQ_RRMW|REG_SETU), 0x80,0x80,
+		(SEQ_RRMW|REG_CCTR), 0x00,0x80
+	};
+	int rc, rest;
+
+	/* send IDENTIFY command */
+	US_DEBUGP("uss725 seq: identify\n");
+	rc = uss725_send_seq(us, seq_identify_cmd, sizeof(seq_identify_cmd));
+	if (rc) {
+		US_DEBUGP("uss725 seq_identify_cmd failed! (%d)\n", rc);
+		return USS725_ERROR;
+	}
+
+	/* wait for DRQ */
+	rc = uss725_wait_bsy(us, BSY_TIMEOUT);
+	if ( rc != WAIT_STATE_DEVICE_DRQ ) {
+		US_DEBUGP("Failed waiting for DRQ\n");
+		return USS725_ERROR;
+	}
+
+	/* send "move data" sequence */
+	US_DEBUGP("uss725 seq: move identify data\n");
+	rc = uss725_send_seq(us, seq_identify_move_data, sizeof(seq_identify_move_data));
+	if (rc) {
+		US_DEBUGP("uss725 seq identify move data failed! (%d)\n", rc);
+		return USS725_ERROR;
+	}
+
+	/* read the data */
+	rc = usb_stor_bulk_transfer_buf(us, 
+			       us->recv_bulk_pipe,
+			       &(((struct uss725_info*)(us->extra))->drive),
+			       sizeof(struct hd_driveid), &rest);
+	if (rc) {
+		US_DEBUGP("uss725 failed reading identify data! (%d)\n", rc);
+		return USS725_ERROR;
+	}
+
+	/* wait for device to finish */
+	rc = uss725_wait_bsy(us, BSY_TIMEOUT);
+	if (rc) {
+		US_DEBUGP("uss725 wait_bsy failed! (%d)\n", rc);
+		return USS725_ERROR;
+	}
+
+	return USS725_GOOD;
+}
+
+int uss725_cmdseq( struct us_data* us,
+		   struct ata_regs* ataRegs )
+{
+	/* line 4548 */
+	struct uss725_info* info = (struct uss725_info *)us->extra;
+	unsigned char buf[128];
+	unsigned char* ptr = buf;
+	int seqBsyBeforeDevSel, seqBsyBeforeCmd, seqBsyAfterCmd, seqErrAfterCmd, seqDrqAfterCmd;
+
+	/* setup sequence header */
+	*ptr++ = 0x00;
+	*ptr++ = 0x00;
+	*ptr++ = SEQ_BLOCKING_BIT;
+
+	/* set the manual reverse bit */
+	*ptr++ = (SEQ_RRMW|REG_CCTR);
+	*ptr++ = REG_CCTR_MANUAL_REVERSE;
+	*ptr++ = REG_CCTR_MANUAL_REVERSE;
+
+	/* poll STATUS for !BSY */
+	*ptr++ = (SEQ_RWRI|REG_ATAA);
+	*ptr++ = ATA_ADDRESS_ALT_STATUS;
+	*ptr++ = (SEQ_RRCM|REG_EPPA);
+	*ptr++ = 0xFF;
+	*ptr++ = 0xFF;
+	*ptr++ = 0x00;
+	*ptr++ = 0x80;
+	seqBsyBeforeDevSel = (ptr - buf) - 3;
+	// -3 for header bytes that the chip doesn't receive
+   
+	/* setup head register */
+	*ptr++ = (SEQ_RWRI|REG_ATAA);
+	*ptr++ = ATA_ADDRESS_DEV_HEAD;
+	*ptr++ = (SEQ_RWRI|REG_EPPA);
+	*ptr++ = ATA_ADDRESS_DEVHEAD_STD | info->DeviceHead;
+
+	/* poll STATUS for !BSY & DRDY */
+	*ptr++ = (SEQ_RWRI|REG_ATAA);
+	*ptr++ = ATA_ADDRESS_ALT_STATUS;
+	*ptr++ = (SEQ_RRCM|REG_EPPA);
+	*ptr++ = 0xFF;
+	*ptr++ = 0xFF;
+	*ptr++ = (0x00            | ATA_STATUS_DRDY);
+	*ptr++ = (ATA_STATUS_BUSY | ATA_STATUS_DRDY);
+	seqBsyBeforeCmd = (ptr - buf) - 3;
+
+	/* setup required ATA regs */
+	if (ataRegs->regFlags & ATA_REGMASK_FEATURES) 
+	{
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_FEATURES;
+		*ptr++ = (SEQ_RWRI|REG_EPPA);
+		*ptr++ = ataRegs->features;
+	}
+	if (ataRegs->regFlags & ATA_REGMASK_SECTOR_COUNT) 
+	{
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_SECT_CNT;
+		*ptr++ = (SEQ_RWRI|REG_EPPA);
+		*ptr++ = ataRegs->sectorCount;
+	}
+	if (ataRegs->regFlags & ATA_REGMASK_SECTOR_NUM) 
+	{
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_SECT_NUM;
+		*ptr++ = (SEQ_RWRI|REG_EPPA);
+		*ptr++ = ataRegs->sectorNum;
+	}
+	if (ataRegs->regFlags & ATA_REGMASK_CYLINDER) 
+	{
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_CYL_HIGH;
+		*ptr++ = (SEQ_RWRI|REG_EPPA);
+		*ptr++ = (unsigned char)(ataRegs->cylinder>>8);
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_CYL_LOW;
+		*ptr++ = (SEQ_RWRI|REG_EPPA);
+		*ptr++ = (unsigned char)ataRegs->cylinder;
+	}
+	if (ataRegs->regFlags & ATA_REGMASK_HEAD) 
+	{
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_DEV_HEAD;
+		*ptr++ = (SEQ_RWRI|REG_EPPA);
+		*ptr++ = (ATA_ADDRESS_DEVHEAD_STD | 
+			  info->DeviceHead | 
+			  ataRegs->head);
+	}
+		
+	/* setup command register */
+	*ptr++ = (SEQ_RWRI|REG_ATAA);
+	*ptr++ = ATA_ADDRESS_COMMAND;
+	*ptr++ = (SEQ_RWRI|REG_EPPA);
+	*ptr++ = (unsigned char)(ataRegs->cmd);
+
+	/* check to determine if to wait for !BSY and check !ERR after cmd */
+	if (ataRegs->cmdFlags & ATA_CMDMASK_NO_CHECK_FOR_BSY_AND_ERR_AFTER_CMD)
+	{
+		US_DEBUGP("   Skipping check for !BSY and ERR\n");
+
+		/* set to some bogus value */
+		seqBsyAfterCmd = seqErrAfterCmd = seqDrqAfterCmd = 0xFF;
+	}
+	else
+	{
+		/* add check for !BSY */
+		if (ataRegs->cmdFlags & ATA_CMDMASK_WILL_XFER_DATA) 
+		{
+			/* set to Alt Status if tranfering data */
+			*ptr++ = (SEQ_RWRI|REG_ATAA);
+			*ptr++ = ATA_ADDRESS_ALT_STATUS;
+		}
+		else
+		{
+			*ptr++ = (SEQ_RWRI|REG_ATAA);
+			*ptr++ = ATA_ADDRESS_STATUS;
+		}
+		/* wait !BSY */
+		*ptr++ = (SEQ_RRCM|REG_EPPA);
+		*ptr++ = 0xFF;
+		*ptr++ = 0xFF;
+		*ptr++ = 0x00;
+		*ptr++ = 0x80;
+		seqBsyAfterCmd = (ptr - buf) - 3;
+
+		*ptr++ = (SEQ_RWRI|REG_ATAA);
+		*ptr++ = ATA_ADDRESS_STATUS;
+
+		/* add check for !ERR */
+		*ptr++ = (SEQ_RRCM|REG_EPPA);
+		*ptr++ = 0x00;
+		*ptr++ = 0x00;
+		*ptr++ = 0x00;
+		*ptr++ = 0x01;
+		seqErrAfterCmd = (ptr - buf) - 3;
+
+		/* check to determine if to wait for DRQ after cmd */
+		if (ataRegs->cmdFlags & ATA_CMDMASK_CHECK_FOR_DRQ_AFTER_CMD) 
+		{
+			*ptr++ = (SEQ_RRCM|REG_EPPA);
+			*ptr++ = 0x00;
+			*ptr++ = 0x00;
+			*ptr++ = ATA_STATUS_DRQ;
+			*ptr++ = ATA_STATUS_DRQ;
+			seqDrqAfterCmd = (ptr - buf) - 3;
+		} 
+		else
+		{
+			/* set to some bogus value */
+			seqDrqAfterCmd = 0xFF;
+		}
+	}
+	/* clear the manual reverse bit */
+	*ptr++ = (SEQ_RRMW|REG_CCTR);
+	*ptr++ = 0x00;
+	*ptr++ = REG_CCTR_MANUAL_REVERSE;
+
+	return uss725_send_seq(us, buf, ptr - buf);
+}
+
+int uss725_write_reg(struct us_data* us, int reg, int data)
+{
+	/* line 7583 */
+	u16 value = (reg << 8) | data;
+
+	if(usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+			   SET_1284_REGISTER, 0x40, value, 0, NULL, 0,
+			   HZ)) {
+		US_DEBUGP("uss725 register write %d = %d failed!\n",
+			  reg,data);
+		return USS725_ERROR;
+	}
+	US_DEBUGP("uss725 register write: %d = %d\n",reg,data);
+
+	return USS725_GOOD;
+}
+
+/**************************************************************************
+ * uss725_soft_reset
+ *
+ * Perform soft reset
+ */
+int uss725_soft_reset(struct us_data* us)
+{
+	if(usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+			   SOFT_RESET, 0x21, 0, 0, NULL, 0, HZ) >= 0) {
+		US_DEBUGP("   USS725 soft reset sent\n");
+		return USS725_GOOD;
+	}
+
+	US_DEBUGP("   Request for USS725 soft reset failed!\n");
+
+	return USS725_ERROR;
+}
+
+/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+/**************************************************************************
+ * uss725_build_sense
+ *                                                                         
+ *  Builds an artificial sense buffer to report the results of a 
+ *  failed command.
+ *                                                                       
+ * RETURNS:
+ *    void
+ */                                                                        
+void uss725_build_sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+        struct uss725_info *info = (struct uss725_info *)us->extra;
+        struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
+        unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
+
+	if(error & MCR_ERR) { /* media changed */
+		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;
+        }
+}
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+int uss725_data_seq_thread(void * data) {
+	struct us_data * us = (struct us_data *) data;
+	struct uss725_info* info = (struct uss725_info *)us->extra;
+	int rc;
+
+	lock_kernel();
+
+	daemonize("uss725");
+	current->flags |= PF_NOFREEZE;
+	flush_signals(current);
+	/* set our name for identification purposes */
+	sprintf(current->comm, "uss725-xfer-%d", us->host->host_no);
+  
+	unlock_kernel();
+
+	/* read/write datas */
+	rc = usb_stor_bulk_transfer_buf(us, 
+			       info->xfer_pipe,
+			       info->xfer_buffer,
+			       info->xfer_len_buffer,&info->xfer_len_buffer);
+
+	if (rc) 
+		US_DEBUGP("uss725 data_seq_thread: failed! (%d)\n", rc);
+	else
+		US_DEBUGP("uss725 data_seq_thread: data ok\n");
+
+	info->exit_code = rc;
+	complete(&(info->notify));
+	return 0;
+}
+
+int uss725_data_seq(struct us_data* us, unsigned char dataDirection, unsigned int length)
+{
+	struct uss725_info* info = (struct uss725_info *)us->extra;
+	unsigned int blocks = length / ATA_BYTES_PER_BLOCK;
+	unsigned char hiXfer = (ATA_BYTES_PER_BLOCK-1) >> 8;
+	unsigned char loXfer = (ATA_BYTES_PER_BLOCK-1) & 0xff;
+	unsigned char seq_data[128];
+	unsigned char * ptr = seq_data;
+	int rc,pid;
+
+	/* seq_data_init */
+  	*ptr++ = (unsigned char)(blocks-1);
+	*ptr++ = (unsigned char)((blocks-1)>>8); 
+	*ptr++ = SEQ_BLOCKING_BIT;
+
+	if (dataDirection == SCSI_DATA_READ) {
+	*ptr++ = (SEQ_RRMW|REG_CCTR); *ptr++ = REG_CCTR_MANUAL_REVERSE; *ptr++ = REG_CCTR_MANUAL_REVERSE;
+	}
+	*ptr++ = (SEQ_RWRI|REG_ATAA); *ptr++ = ATA_ADDRESS_ALT_STATUS;
+  	*ptr++ = (SEQ_RRCM|REG_EPPA); *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = ATA_STATUS_DRQ; *ptr++ = ATA_STATUS_DRQ;
+		/* enable flow data to buffer */
+  	*ptr++ = (SEQ_RRMW|REG_SETU); *ptr++ = 0x00; *ptr++ = REG_SETU_HOLD_BULK;
+
+	if (dataDirection == SCSI_DATA_READ) {
+		/* seq_data_in */
+		/* Set Direction bit to 1 (Input Mode): */
+  	*ptr++ = (SEQ_RRMW|REG_CTRL); *ptr++ = REG_CTRL_DIRECTION_IN; *ptr++ = REG_CTRL_DIRECTION_IN;
+  	*ptr++ = (SEQ_RWRI|REG_ATAA); *ptr++ = ATA_ADDRESS_DATA;
+	*ptr++ = (SEQ_WBIB|0x00); *ptr++ =     hiXfer; *ptr++ = loXfer;
+	*ptr++ = (SEQ_RRMW|REG_CTRL); *ptr++ = 0x00; *ptr++ = REG_CTRL_DIRECTION_IN;
+	} else {
+		/* seq_data_out */
+		/* Set Direction bit to 0 (Output Mode): */
+  	*ptr++ = (SEQ_RWRI|REG_ATAA); *ptr++ = ATA_ADDRESS_DATA;
+  	*ptr++ = (SEQ_WBOB|0x00); *ptr++ =     hiXfer; *ptr++ = loXfer;
+	}
+		/* seq_data_end */
+  	*ptr++ = (SEQ_RRMW|REG_SETU); *ptr++ = REG_SETU_HOLD_BULK; *ptr++ = REG_SETU_HOLD_BULK;
+  	*ptr++ = (SEQ_RWRI|REG_ATAA); *ptr++ = ATA_ADDRESS_ALT_STATUS;
+  	*ptr++ = (SEQ_RRCM|REG_EPPA); *ptr++ = 0xFF; *ptr++ = 0xFF; *ptr++ = 0x00; *ptr++ = ATA_STATUS_BUSY;
+  	*ptr++ = (SEQ_RWRI|REG_ATAA); *ptr++ = ATA_ADDRESS_STATUS;
+  	*ptr++ = (SEQ_RRCM|REG_EPPA); *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = ATA_STATUS_ERROR;
+
+	
+	/* wait for DRQ */
+	rc = uss725_wait_bsy(us, BSY_TIMEOUT);
+	if ( rc != WAIT_STATE_DEVICE_DRQ ) {
+		US_DEBUGP("uss725 data_seq: Failed waiting for DRQ\n");
+		return USS725_ERROR;
+	}
+
+	init_completion(&(info->notify));
+	/* start thread */
+        pid = kernel_thread(uss725_data_seq_thread, us,
+			    CLONE_VM);
+	if (pid < 0) {
+	  US_DEBUGP("uss725 data_seq: Unable to start thread\n");
+	  return USS725_ERROR;
+	}
+
+	/* send "move data" sequence */
+        rc = uss725_send_seq(us, seq_data, ptr - seq_data);
+	if (rc) {
+	  US_DEBUGP("uss725 data_seq: seq_data failed! (%d)\n", rc);
+	  return USS725_ERROR;
+	}
+
+	/* wait thread finish */
+	wait_for_completion(&(info->notify));
+	US_DEBUGP("uss725 data_seq: wait ok\n");
+	  
+        return USS725_GOOD;
+}
+
+/**************************************************************************
+ * Transfer one SCSI scatter-gather buffer via bulk transfer
+ *
+ * Note that this function is necessary because we want the ability to
+ * use scatter-gather memory.  Good performance is achieved by a combination
+ * of scatter-gather and clustering (which makes each chunk bigger).
+ *
+ * Note that the lower layer will always retry when a NAK occurs, up to the
+ * timeout limit.  Thus we don't have to worry about it for individual
+ * packets.
+ */
+int uss725_transfer_partial( struct us_data *us, 
+				    unsigned char dataDirection,
+				    char * buf, unsigned int length )
+{
+	struct uss725_info* info = (struct uss725_info *)us->extra;
+        int result;
+	int partial;
+
+        US_DEBUGP("uss725_transfer_partial(): xfer %d bytes\n", length);
+
+	info->xfer_buffer = buf;
+	info->xfer_len_buffer = length;
+        /* transfer the data */
+	if (dataDirection == SCSI_DATA_READ) {
+		US_DEBUGP("uss725_transfer_partial(): reading ...\n");
+		info->xfer_pipe = us->recv_bulk_pipe;
+        } else {
+		US_DEBUGP("uss725_transfer_partial(): writing ...\n");
+		info->xfer_pipe = us->send_bulk_pipe;
+	}
+
+	if (uss725_data_seq(us,dataDirection,length) != USS725_GOOD) {
+		US_DEBUGP("uss725_transfer_partial(): device ERROR\n");
+		return USS725_TRANSPORT_ERROR;
+	}
+
+	partial = info->xfer_len_buffer;
+	result = info->exit_code;
+        US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
+                  result, partial, length);
+
+	/* if we stall, we need to clear it before we go on */
+	if (result == -EPIPE) {
+                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", info->xfer_pipe);
+                usb_stor_clear_halt(us, info->xfer_pipe);
+                return USS725_TRANSPORT_FAILED;
+	}
+    
+        /* did we send all the data? */
+        if (info->xfer_len_buffer == length) {
+                US_DEBUGP("uss725_transfer_partial(): transfer complete\n");
+                return USS725_TRANSPORT_GOOD;
+	}
+
+        /* uh oh... we have an error code, so something went wrong. */
+        if (result) {
+                /* NAK - that means we've retried a few times already */
+                if (result == -ETIMEDOUT) {
+                        US_DEBUGP("uss725_transfer_partial(): device NAKed\n");
+                        return USS725_TRANSPORT_FAILED;
+                }
+
+                /* -ENOENT -- we canceled this transfer */
+                if (result == -ENOENT) {
+                        US_DEBUGP("uss725_transfer_partial(): transfer aborted\n");
+                        return USS725_TRANSPORT_ERROR;
+		}
+
+                /* the catch-all case */
+                US_DEBUGP("uss725_transfer_partial(): unknown error\n");
+                return USS725_TRANSPORT_FAILED;
+        }
+
+        /* no error code, so we must have transferred some data, 
+         * just not all of it */
+        return USS725_TRANSPORT_SHORT;
+}
+
+/**************************************************************************
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses us_transfer_partial to achieve it's goals -- this
+ * function simply determines if we're going to use scatter-gather or not,
+ * and acts appropriately.  For now, it also re-interprets the error codes.
+ *
+ * Scatter-gathering mode (multiple tranfer_partial call) : 387.47 kB/sec
+ * Scatter-gathering mode (1 tranfer_partial call) : 836.56 kB/sec
+ */
+
+void uss725_transfer( struct us_data *us, struct scsi_cmnd *srb )
+{
+        int i;
+        struct scatterlist *sg;
+        unsigned int total_transferred = 0;
+        int result = USS725_TRANSPORT_ERROR;
+        unsigned int transfer_amount = srb->request_bufflen;
+
+        /* are we scatter-gathering? */
+        if (srb->use_sg) {
+		US_DEBUGP("   uss725 : scatter-gathering\n");
+
+                /* loop over all the scatter gather structures and 
+                 * make the appropriate requests for each, until done
+                 */
+                sg = (struct scatterlist *) srb->request_buffer;
+                for (i = 0; i < srb->use_sg; i++) {
+
+                        /* transfer the lesser of the next buffer or the
+                         * remaining data */
+                        if (transfer_amount - total_transferred >= 
+                            sg[i].length) {
+                                result = uss725_transfer_partial(us, 
+                                                                 srb->sc_data_direction,
+                                                                 sg_address(sg[i]), 
+                                                                 sg[i].length);
+                                total_transferred += sg[i].length;
+                        } else
+                                result = uss725_transfer_partial(us, 
+                                                                 srb->sc_data_direction,                            
+                                                                 sg_address(sg[i]), 
+                                                                 transfer_amount - total_transferred);
+
+                        /* if we get an error, end the loop here */
+                        if (result)
+                                break;
+                }
+        }
+        else
+                /* no scatter-gather, just make the request */
+                result = uss725_transfer_partial(us, 
+                                                 srb->sc_data_direction,
+                                                 srb->request_buffer, 
+                                                 transfer_amount);
+
+        /* return the result in the data structure itself */
+        srb->result = result;
+}
+
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+/**************************************************************************
+ *  uss725_action
+ *
+ * Routine for sending commands to the uss725
+ *
+ * RETURNS:
+ *    USS status code
+ */
+int uss725_action( struct us_data *us, int action, void* pointer, int value)
+{
+	struct uss725_info *info = (struct uss725_info *)us->extra;
+	int status = USS725_GOOD;
+
+	switch ( action ) {
+	case ACTION_READ_STATUS: {
+		unsigned char regs[8];
+		US_DEBUGP("   uss725_action(READ_STATUS)\n");
+		if((status = uss725_read_ata_reg(us,ATA_ADDRESS_ALT_STATUS,&regs[IDE_STATUS_OFFSET])) != USS725_GOOD)
+			break;
+		if((status = uss725_read_ata_reg(us,ATA_ADDRESS_ERROR,&regs[IDE_ERROR_OFFSET])) != USS725_GOOD)
+			break;
+		if((status = uss725_read_ata_reg(us,ATA_ADDRESS_CYL_LOW,&regs[IDE_LCYL_OFFSET])) != USS725_GOOD)
+			break;
+		if((status = uss725_read_ata_reg(us,ATA_ADDRESS_CYL_HIGH,&regs[IDE_HCYL_OFFSET])) != USS725_GOOD)
+			break;
+		memcpy(pointer,regs,8);
+		break;
+	}
+	case ACTION_ENUM:
+		US_DEBUGP("   uss725_action(ENUM,0x%02x)\n", ATA_ADDRESS_DEVHEAD_STD|value);
+		status = uss725_write_ata_reg(us,ATA_ADDRESS_DEV_HEAD, ATA_ADDRESS_DEVHEAD_STD|value);
+		break;
+
+	case ACTION_RESET:
+		US_DEBUGP("   uss725_action(RESET)\n");
+		status = uss725_write_ata_reg(us, 
+					      ATA_ADDRESS_DEV_CNTRL, 
+					      ATA_DC_RESET_CONTROLLER);
+		break;
+
+	case ACTION_REENABLE:
+		US_DEBUGP("   uss725_action(REENABLE)\n");
+		status = uss725_write_ata_reg(us, 
+					      ATA_ADDRESS_DEV_CNTRL, 
+					      ATA_DC_REENABLE_CONTROLLER);
+		break;
+
+	case ACTION_SOFT_RESET:
+		US_DEBUGP("   uss725_action(SOFT_RESET)\n");
+		if((status = uss725_write_ata_reg(us, 
+						  ATA_ADDRESS_DEV_HEAD, 
+						  ATA_ADDRESS_DEVHEAD_STD | info->DeviceHead)) != USS725_GOOD)
+			break;
+		status = uss725_write_ata_reg(us, 
+					      ATA_ADDRESS_COMMAND, 
+					      WIN_SRST);
+		break;
+
+	case ACTION_IDENTIFY:
+		US_DEBUGP("   uss725_action(IDENTIFY)\n");
+		   /* Only ATA is supported */
+		status = uss725_identify(us,FALSE);
+		break;
+
+	default:
+		US_DEBUGP("Error: Undefined action %d\n",action);
+		break;
+	}
+
+	if (status != USS725_GOOD) {
+		US_DEBUGP("   uss725_action(0x%02x) error: %d\n",action,status);
+		/* need to reset device here */
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * uss725_read_regs
+ *                                                                         
+ * Read ATA Registers
+ *
+ * RETURNS:
+ *    USS status code
+ */                                                                        
+int uss725_read_regs( struct us_data *us )
+{
+	struct uss725_info *info = (struct uss725_info *)us->extra;
+	int transferStatus; /* fix for gcc2.9x (McMCC)*/
+	int retStatus = USS725_GOOD;
+
+	US_DEBUGP("Entering uss725_IssueATAReadRegs\n");
+
+	transferStatus = uss725_action(us, ACTION_READ_STATUS,
+				       info->ATARegs, sizeof(info->ATARegs));
+	if (transferStatus != USS725_GOOD) {
+		US_DEBUGP("   Error reading ATA registers\n");
+		retStatus = USS725_ERROR;
+        } else {
+		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.
+ */
+void uss725_invoke_transport( struct us_data *us, 
+			      struct scsi_cmnd *srb)
+{
+	int need_auto_sense = 0;
+
+	/* send the command to the transport layer */
+	uss725_transfer(us,srb);
+
+	switch (srb->result) {
+
+	case USS725_TRANSPORT_GOOD:
+		/* Indicate a good result */
+		srb->result = GOOD;
+		break;
+
+	case USS725_TRANSPORT_FAILED:
+		US_DEBUGP("-- transport indicates command failure\n");
+		need_auto_sense = 1;
+		break;
+
+	case USS725_TRANSPORT_ERROR:
+		US_DEBUGP("-- transport indicates transport failure\n");
+		srb->result = DID_ERROR << 16;
+		break;
+
+	case USS725_TRANSPORT_SHORT:
+		if (!((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;
+		}
+		break;
+    
+	default:
+		US_DEBUGP("-- transport indicates unknown failure\n");   
+		srb->result = DID_ERROR << 16;
+		break;
+	}
+
+	if (need_auto_sense && uss725_read_regs(us) == USS725_GOOD)
+		uss725_build_sense(us, srb);
+
+	/* Regardless of auto-sense, if we _know_ we have an error
+	 * condition, show that in the result code
+	 */
+	if (srb->result == USS725_TRANSPORT_FAILED)
+		srb->result = CHECK_CONDITION;
+}
+
+
+
+/**************************************************************************
+ * uss725_atapi_soft_reset
+ *                                                                         
+ * Perform an Atapi Soft Reset on the device
+ *
+ * RETURNS:
+ *    NT status code
+ */                                                                        
+int uss725_atapi_soft_reset( struct us_data *us ) 
+{
+	int retStatus = USS725_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering uss725_atapi_soft_reset\n");
+
+	transferStatus = uss725_action( us, ACTION_SOFT_RESET, NULL, 0 );
+	if (transferStatus != USS725_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error issuing Atapi Soft Reset\n");
+		retStatus = USS725_ERROR;
+        }
+
+	US_DEBUGP("Leaving uss725_atapi_soft_reset %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * uss725_srst
+ *                                                                         
+ * Perform an SRST on the device
+ *
+ * RETURNS:
+ *    USS status code
+ */                                                                        
+int uss725_srst( struct us_data *us ) 
+{
+	int retStatus = USS725_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering uss725_SRST\n");
+
+	transferStatus = uss725_action( us, ACTION_RESET, NULL, 0 );
+
+	/* check to see if this request failed */
+	if (transferStatus != USS725_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error issuing SRST\n");
+		retStatus = USS725_ERROR;
+        } else {
+		/* delay 10ms to give the drive a chance to see it */
+		msleep(10);
+
+		transferStatus = uss725_action( us, ACTION_REENABLE, NULL, 0 );
+		if (transferStatus != USS725_TRANSPORT_GOOD) {
+			US_DEBUGP("   Error taking drive out of reset\n");
+			retStatus = USS725_ERROR;
+		} else {
+			/* delay 50ms to give the drive a chance to recover after SRST */
+			msleep(50);
+		}
+        }
+
+	US_DEBUGP("Leaving uss725_srst %08X\n", retStatus);
+	return retStatus;
+}
+
+/**************************************************************************
+ * uss725_ide_ms_dev
+ *
+ * Check master and slave device status 
+ *
+ */
+int uss725_ide_ms_dev(int regstat, unsigned char master_slave)
+{
+	int status = 0;
+	
+	if (regstat & SENSE_ERRCODE_VALID) {
+	    US_DEBUGP("Device detect master or slave: failed, try again...\n");
+	    status = 1;
+	    return status;
+	}
+	
+	US_DEBUGP("Device detect %s: ", master_slave == IDE_MASTER ? "master" : "slave");
+	switch (regstat & SENSE_ERRCODE) {
+		case 0: US_DEBUGPX("not passed");
+			status = 0;
+			break;
+		case 1: US_DEBUGPX("passed");
+			status = 1;
+			break;
+		case 2: US_DEBUGPX("formatter device error");
+			status = 2;
+			break;
+		case 3: US_DEBUGPX("sector buffer error");
+			status = 3;
+			break;
+		case 4: US_DEBUGPX("ECC circuitry error");
+			status = 4;
+			break;
+		case 5: US_DEBUGPX("controlling MPU error");
+			status = 5;
+			break;
+		default: US_DEBUGPX("unknown error (0x%02x)", regstat); 
+			 status = 0;
+			 break;
+	}
+	US_DEBUGPX("\n");
+	return status;
+}	
+
+/**************************************************************************
+ * uss725_try_enum
+ *                                                                         
+ * Helper function for uss725_manual_enum(). Does ENUM and READ_STATUS
+ * and tries to analyze the status registers
+ *
+ * RETURNS:
+ *    USS status code
+ */                                                                        
+int uss725_try_enum(struct us_data *us, unsigned char master_slave,
+			   int detect )
+{
+	int status = USS725_GOOD;
+	unsigned char regs[8];
+	unsigned long endTime;
+	struct uss725_info *info = (struct uss725_info *)us->extra;
+
+	if ( detect )
+		endTime = jiffies + USS725_ENUM_DETECT_TIMEOUT * HZ;
+	else
+		endTime = jiffies + USS725_ENUM_BSY_TIMEOUT * HZ;
+
+	/* loop until we detect !BSY or timeout */
+	while(TRUE) {
+
+		status = uss725_action( us, ACTION_ENUM, NULL, master_slave );
+		if ( status != USS725_GOOD )
+			break;
+
+		status = uss725_action( us, ACTION_READ_STATUS, 
+					regs, sizeof(regs) );
+		if ( status != USS725_GOOD )
+			break;
+		
+		/* check master and slave status device.                */
+		/* Fix for CS(CABLE SELECT) mode device seting detect   */
+		/* (ZIV1 "http://www.ziv.ru" and other USB HDD device). */
+		if (uss725_ide_ms_dev(regs[IDE_ERROR_OFFSET], master_slave) != 1)
+		{
+			status = USS725_ERROR;
+			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
+			*/
+			US_DEBUGP("   Identified ATAPI device\n");
+			info->DeviceHead = master_slave;
+			      
+			status = uss725_atapi_soft_reset(us);
+			break;
+		} else {
+ 			US_DEBUGP("   Not ATA, not ATAPI. Weird.\n");
+			status = USS725_ERROR;
+			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;
+		} else {
+			/* wait a while for response */
+			msleep(500);
+		}
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * uss725_manual_enum
+ *                                                                         
+ * Determines if the drive attached is an ATA or ATAPI and if it is a
+ * master or slave.
+ *
+ * RETURNS:
+ *    USS status code
+ */                                                                        
+int uss725_manual_enum(struct us_data *us)
+{
+	int retStatus = USS725_GOOD;
+
+	US_DEBUGP("Entering uss725_manual_enum\n");
+
+	/* master or slave? */
+	retStatus = uss725_srst(us);
+
+	if (retStatus == USS725_GOOD)
+		retStatus = uss725_try_enum( us, IDE_MASTER, TRUE );
+		
+	if (retStatus != USS725_GOOD)
+		retStatus = uss725_try_enum( us, IDE_SLAVE, TRUE );
+
+	US_DEBUGP("Leaving uss725_manual_enum %08X\n", retStatus);
+	return(retStatus);
+}
+
+
+/**************************************************************************
+ * uss725_get_inquiry_data
+ *
+ * Get inquiry data
+ *
+ * RETURNS:
+ *    USS status code
+ */
+int uss725_get_inquiry_data( struct us_data *us )
+{
+	struct uss725_info *info = (struct uss725_info *)us->extra;
+	int retStatus = USS725_GOOD;
+
+	US_DEBUGP("Entering uss725_get_inquiry_data\n");
+
+	/* set default to Master */
+	info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD;
+
+	/* attempt to manually enumerate this device */
+	retStatus = uss725_manual_enum(us);
+	if (retStatus == USS725_GOOD) {
+		int transferStatus;
+
+		/* check for an ATA device */
+		if (info->DeviceFlags & DF_ATA_DEVICE) {
+			/* this must be an ATA device */
+			/* perform an ATA Commmand Identify */
+			transferStatus = uss725_action( us, ACTION_IDENTIFY,
+							&info->drive, 
+							sizeof(struct hd_driveid) );
+			if (transferStatus != USS725_TRANSPORT_GOOD) {
+				/* Error issuing ATA Command Identify */
+				US_DEBUGP("   Error issuing ATA Command Identify\n");
+				retStatus = USS725_ERROR;
+			} else {
+				/* ATA Command Identify successful */
+				int i;
+				__u16 *src, *dest;
+				ide_fix_driveid(&info->drive);
+
+				US_DEBUGP("   Identify Data Structure:\n");
+				US_DEBUGP("      config = 0x%x\n", info->drive.config);
+				US_DEBUGP("      cyls = 0x%x\n", info->drive.cyls);
+				US_DEBUGP("      heads = 0x%x\n", info->drive.heads);
+				US_DEBUGP("      track_bytes = 0x%x\n", info->drive.track_bytes);
+				US_DEBUGP("      sector_bytes = 0x%x\n", info->drive.sector_bytes);
+				US_DEBUGP("      sectors = 0x%x\n", info->drive.sectors);
+				US_DEBUGP("      serial_no[0] = 0x%x\n", info->drive.serial_no[0]);
+				US_DEBUGP("      buf_type = 0x%x\n", info->drive.buf_type);
+				US_DEBUGP("      buf_size = 0x%x\n", info->drive.buf_size);
+				US_DEBUGP("      ecc_bytes = 0x%x\n", info->drive.ecc_bytes);
+				US_DEBUGP("      fw_rev[0] = 0x%x\n", info->drive.fw_rev[0]);
+				US_DEBUGP("      model[0] = 0x%x\n", info->drive.model[0]);
+				US_DEBUGP("      max_multsect = 0x%x\n", info->drive.max_multsect);
+				US_DEBUGP("      dword_io = 0x%x\n", info->drive.dword_io);
+				US_DEBUGP("      capability = 0x%x\n", info->drive.capability);
+				US_DEBUGP("      tPIO = 0x%x\n", info->drive.tPIO);
+				US_DEBUGP("      tDMA = 0x%x\n", info->drive.tDMA);
+				US_DEBUGP("      field_valid = 0x%x\n", info->drive.field_valid);
+				US_DEBUGP("      cur_cyls = 0x%x\n", info->drive.cur_cyls);
+				US_DEBUGP("      cur_heads = 0x%x\n", info->drive.cur_heads);
+				US_DEBUGP("      cur_sectors = 0x%x\n", info->drive.cur_sectors);
+				US_DEBUGP("      cur_capacity = 0x%x\n", (info->drive.cur_capacity1 << 16) + info->drive.cur_capacity0 );
+				US_DEBUGP("      multsect = 0x%x\n", info->drive.multsect);
+				US_DEBUGP("      lba_capacity = 0x%x\n", info->drive.lba_capacity);
+				US_DEBUGP("      command_set_1 = 0x%x\n", info->drive.command_set_1);
+				US_DEBUGP("      command_set_2 = 0x%x\n", info->drive.command_set_2);
+
+				memset(&info->InquiryData, 0, sizeof(info->InquiryData));
+
+				/* Standard IDE interface only supports disks */
+				info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE;
+
+				/* Fix-up the return data from an INQUIRY command to show 
+				 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+				 * in Linux.
+				 */
+				info->InquiryData.Versions = 0x2;
+
+				/* The length must be at least 36 (5 + 31) */
+				info->InquiryData.AdditionalLength = 0x1F;
+
+				if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) {
+					/* set the removable bit */
+					info->InquiryData.RemovableMedia = 1;
+					info->DeviceFlags |= DF_REMOVABLE_MEDIA;
+				}
+
+				/* Fill in vendor identification fields */
+				src = (__u16*)info->drive.model;
+				dest = (__u16*)info->InquiryData.VendorId;
+				for (i=0;i<4;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__u16*)(info->drive.model+8);
+				dest = (__u16*)info->InquiryData.ProductId;
+				for (i=0;i<8;i++)
+					dest[i] = be16_to_cpu(src[i]);
+
+				src = (__u16*)info->drive.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 (info->drive.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 
+			 */
+			US_DEBUGP("ATAPI device not supported\n");
+			retStatus = USS725_ERROR;
+		}
+        }
+
+	US_DEBUGP("Leaving uss725_get_inquiry_data %08X\n", retStatus);
+
+	return(retStatus);
+}
+
+/**************************************************************************
+ * uss725_data_copy
+ *                                                                         
+ * Copy data into the srb request buffer.  Use scatter gather if required.
+ *
+ * RETURNS:
+ *    void
+ */                                                                        
+void uss725_data_copy(struct scsi_cmnd *srb, char * src, int length)
+{
+	unsigned int len = length;
+	struct scatterlist *sg;
+
+	if (srb->use_sg) {
+		int i;
+		unsigned int total = 0;
+
+		/* Add up the sizes of all the sg segments */
+		sg = (struct scatterlist *) srb->request_buffer;
+		for (i = 0; i < srb->use_sg; i++)
+			total += sg[i].length;
+
+		if (length > total)
+			len = total;
+
+		total = 0;
+
+		/* Copy data into sg buffer(s) */
+		for (i = 0; i < srb->use_sg; i++) {
+			if ((len > total) && (len > 0)) {
+				/* transfer the lesser of the next buffer or the
+				 * remaining data */
+				if (len - total >= sg[i].length) {
+					memcpy(sg_address(sg[i]), src + total, sg[i].length);
+					total += sg[i].length;
+				} else {
+					memcpy(sg_address(sg[i]), src + total, len - total);
+					total = len;
+				}
+			} 
+			else
+				break;
+		}
+	} else	{
+		/* Make sure length does not exceed buffer length */
+		if (length > srb->request_bufflen)
+			len = srb->request_bufflen;
+
+		if (len > 0 && src)
+			memcpy(srb->request_buffer, src, len);
+	}
+}
+
+/**************************************************************************
+ * uss725_transport
+ *                                                                         
+ * Translate SCSI commands to ATA commands, and transport it
+ *
+ * RETURNS:
+ *    USB_STOR_TRANSPORT_GOOD 
+ *    FALSE otherwise
+ */                                                                        
+int uss725_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+	struct uss725_info *info = (struct uss725_info *)us->extra;
+	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 };
+	struct ata_regs ataRegs; 
+	int status = USB_STOR_TRANSPORT_GOOD;
+
+	memset(&ataRegs, 0, sizeof(struct ata_regs));
+
+	/* SCSI Command */
+	switch (srb->cmnd[0]) {
+	case INQUIRY:
+		US_DEBUGP("   ATA OUT - INQUIRY\n");
+
+		if (srb->request_bufflen > sizeof(struct inquiry_data))
+			srb->request_bufflen = sizeof(struct inquiry_data);
+
+		/* copy InquiryData */
+		uss725_data_copy(srb, (char *) &info->InquiryData, srb->request_bufflen);
+		srb->result = GOOD;
+		break;
+
+	case MODE_SENSE:
+	case TEST_UNIT_READY:
+		US_DEBUGP("   ATA OUT - SCSIOP_MODE_SENSE,SCSIOP_TEST_UNIT_READY\n");
+
+		/* Initialize the return buffer */
+		uss725_data_copy(srb, (char *) &senseData, 8);
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataRegs.regFlags = 0;
+			ataRegs.cmdFlags = 0;
+			ataRegs.cmd = WIN_GETMEDIASTATUS;
+			status = uss725_cmdseq(us, &ataRegs);
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Media Status not supported, just report okay\n");
+			srb->result = GOOD;
+		}
+		break;
+
+	case READ_CAPACITY: {
+		unsigned long capacity;
+		struct read_capacity_data readCapacityData;
+
+		US_DEBUGP("   ATA OUT - SCSIOP_READ_CAPACITY\n");
+
+		if (info->drive.capability & CAPABILITY_LBA ) {
+			capacity = info->drive.lba_capacity - 1;
+		} else {
+			capacity = (info->drive.heads *
+				    info->drive.cyls *
+				    info->drive.sectors) - 1;
+		}
+		readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
+		readCapacityData.BytesPerBlock = cpu_to_be32(ATA_BYTES_PER_BLOCK);
+
+		if (srb->request_bufflen > sizeof(struct read_capacity_data))
+			srb->request_bufflen = sizeof(struct read_capacity_data);
+
+		uss725_data_copy(srb, (char *) &readCapacityData, srb->request_bufflen);
+		srb->result = GOOD;
+		break;
+	}
+
+	case READ_10:
+		US_DEBUGP("   ATA OUT - SCSIOP_READ\n");
+
+		lba = *(unsigned long *)&srb->cmnd[2]; 
+		lba = cpu_to_be32(lba);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (info->drive.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 % info->drive.sectors) + 1);
+			cylinder = (unsigned short)(lba / (info->drive.sectors *
+							   info->drive.heads));
+			head = (unsigned char)((lba / info->drive.sectors) %
+					       info->drive.heads);
+		}
+		ataRegs.regFlags = 
+			ATA_REGMASK_SECTOR_COUNT | 
+			ATA_REGMASK_SECTOR_NUM | 
+			ATA_REGMASK_CYLINDER | 
+			ATA_REGMASK_HEAD;
+		ataRegs.cmdFlags = ATA_CMDMASK_WILL_XFER_DATA;// | ATA_CMDMASK_CHECK_FOR_DRQ_AFTER_CMD;
+		ataRegs.sectorCount = blockCount;
+		ataRegs.sectorNum = sectnum;
+		ataRegs.cylinder = cylinder;
+		ataRegs.head = head;
+		ataRegs.cmd = WIN_READ;
+		
+		if((status = uss725_cmdseq(us, &ataRegs) != USS725_GOOD))
+			break;
+		uss725_invoke_transport(us,srb);
+		break;
+
+	case WRITE_10:
+		US_DEBUGP("   ATA OUT - SCSIOP_WRITE\n");
+
+		lba = *(unsigned long *)&srb->cmnd[2]; 
+		lba = cpu_to_be32(lba);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (info->drive.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 % info->drive.sectors) + 1);
+			cylinder = (unsigned short)(lba / (info->drive.sectors * info->drive.heads));
+			head = (unsigned char)((lba / info->drive.sectors) % info->drive.heads);
+		}
+		ataRegs.regFlags = 
+			ATA_REGMASK_SECTOR_COUNT | 
+			ATA_REGMASK_SECTOR_NUM | 
+			ATA_REGMASK_CYLINDER | 
+			ATA_REGMASK_HEAD;
+		ataRegs.cmdFlags = ATA_CMDMASK_WILL_XFER_DATA | ATA_CMDMASK_CHECK_FOR_DRQ_AFTER_CMD;
+		ataRegs.sectorCount = blockCount;
+		ataRegs.sectorNum = sectnum;
+		ataRegs.cylinder = cylinder;
+		ataRegs.head = head;
+		ataRegs.cmd = WIN_WRITE;
+
+		if((status = uss725_cmdseq(us, &ataRegs) != USS725_GOOD))
+			break;
+		uss725_invoke_transport(us,srb);
+		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]);
+			ataRegs.regFlags = 0;
+			ataRegs.cmdFlags = 0;
+			ataRegs.cmd = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK;
+			status = uss725_cmdseq(us, &ataRegs);
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Not removeable media, just report okay\n");
+			srb->result = GOOD;
+		}
+		break;
+
+	case START_STOP:    
+		US_DEBUGP("   ATA OUT - SCSIOP_START_STOP_UNIT\n");
+		US_DEBUGP("   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+
+		/* Initialize the return buffer */
+		uss725_data_copy(srb, (char *) &senseData, 8);
+
+		ataRegs.regFlags = 0;
+		ataRegs.cmdFlags = 0;
+		if ((srb->cmnd[4] & 0x3) == 0x2) {
+			US_DEBUGP("   Media Eject\n");
+			ataRegs.cmd = WIN_MEDIAEJECT;
+			status = uss725_cmdseq(us, &ataRegs);
+		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
+			US_DEBUGP("   Get Media Status\n");
+			ataRegs.cmd = WIN_GETMEDIASTATUS;
+			status = uss725_cmdseq(us, &ataRegs);
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Nothing to do, just report okay\n");
+			srb->result = GOOD;
+		}
+		break;
+
+	default:
+		US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]);
+		srb->result = DID_ERROR << 16;
+		break;
+	}
+
+	return(status);
+}
+
+/**************************************************************************
+ * uss725_init_device
+ *                                                                         
+ * Initialize the USS725 device registers.
+ *
+ * RETURNS:
+ *    USS status code
+ */                                                                        
+int uss725_init_device(struct us_data* us) {
+	unsigned char seq_init_falstaff[] = {
+		0x00,0x00,SEQ_BLOCKING_BIT,    // Loop Count (WORD) & Block bit
+		(SEQ_RRMW|REG_CTRL),0x00,0x04, // if using nInit as reset, set RESET- bit high
+		(SEQ_NOOP|0x0F),0xFF,          // wait for reset to take affect
+		(SEQ_RRMW|REG_CTRL),0x04,0x04  // if using nInit as reset, set RESET- bit low
+	};
+
+#if 0
+	unsigned char seq_init_falstaff_lite[]={
+		0x00,0x00,SEQ_BLOCKING_BIT, // Loop Count (WORD) & Block bit (bit 8 of BYTE)
+	        (SEQ_RRMW|REG_CTRL),0x04,0x0C, // Put falstaff lite in Status mode
+	        (SEQ_NOOP|0x0F),0xFF,          // wait for a while before check status
+		(SEQ_RRCM|REG_STAT),0xFF,0xFF, 0x18, 0x18, // Wait for status to report Device Opterational
+	        (SEQ_RRMW|REG_CTRL),0x0C,0x0C  // Put falstaff lite device in Run/Charge mode
+	};
+#endif
+
+	unsigned char seq_init_device[] = {
+		0x00,0x00,SEQ_BLOCKING_BIT,    // Loop Count (WORD) & Block bit (bit 8 of BYTE)
+		(SEQ_RRMW|REG_CCTR),0x40,0x40, // Set Slow RRCM bit
+		(SEQ_RRMW|REG_CTRL),0x80,0x80, // Set RESET- bit low
+		(SEQ_RRMW|REG_ECRR),0xE0,0xE0, // Set into ATA Mode
+		(SEQ_RRMW|REG_CCTR),0x80,0x80, // Set Reverse Bit 
+		(SEQ_RRMW|REG_SETU),REG_SETU_FILTER_SFT_OVERRIDE,
+		REG_SETU_FILTER_SFT_OVERRIDE,  // Disable digital filtering
+		(SEQ_RWRI|REG_TIMO),0x00,      // Set to Timeout Register to 0
+      		(SEQ_RRMW|REG_CTRL),0x00,0x20, // Set Direction bit to 0 (Output Mode)
+		(SEQ_RRMW|REG_SETU),0x80,0x80, // Set Hold Bulk bit to 1 (don't allow bulk transfer)
+		(SEQ_NOOP|0x04),0xAA,          // wait for a while before (approx. 20ms)
+	};
+
+	int rc = USS725_ERROR;
+
+	do {
+		if (uss725_soft_reset(us))
+			break;
+
+		if (uss725_write_reg(us, REG_CCTR, 0x58))
+			break;
+
+		US_DEBUGP("Init falstaff\n");
+		if (uss725_send_seq(us, seq_init_falstaff, 
+				    sizeof(seq_init_falstaff)))
+			break;
+
+		US_DEBUGP("Init device\n");
+		if (uss725_send_seq(us, seq_init_device, 
+				    sizeof(seq_init_device)))
+			break;
+
+		rc = USS725_GOOD;
+	} while (0);
+
+	return rc;
+}
+
+/**************************************************************************
+ * uss725_init_info
+ *                                                                         
+ * Allocates (if necessary) and initializes the driver structure.
+ *
+ * RETURNS:
+ *    USS status code
+ */                                                                        
+int uss725_init_info(struct us_data *us)
+{
+	int retStatus = USS725_GOOD;
+
+	if (!us->extra) {
+		us->extra = (void *) kmalloc(sizeof(struct uss725_info), GFP_KERNEL);
+		if (!us->extra) {
+			US_DEBUGP("ERROR - kmalloc failure\n");
+			retStatus = USS725_ERROR;
+		}
+        }
+
+	if (retStatus == USS725_GOOD) {
+		memset(us->extra, 0, sizeof(struct uss725_info));
+        }
+
+	return(retStatus);
+}
+
+/**************************************************************************
+ * Initialization for the USS725 
+ */
+
+int uss725_init(struct us_data *us)
+{
+	US_DEBUGP("USS725 Initialization...\n");
+
+	/* Initialize USS725 info struct */
+	if (uss725_init_info(us) == USS725_ERROR) {
+		US_DEBUGP("ERROR Initializing USS725 Info struct\n");
+		return USS725_ERROR;
+        } 
+
+	if (uss725_init_device(us) != USS725_GOOD) {
+		US_DEBUGP("USS725 init_device Failure\n");
+		return USS725_ERROR;
+        }
+
+	/* Get device specific data */
+	if (uss725_get_inquiry_data(us) != USS725_GOOD) {
+		US_DEBUGP("USS725 Initialization Failure\n");
+		return USS725_ERROR;
+	}
+
+	US_DEBUGP("USS725 Initialization complete\n");
+
+	return USS725_GOOD;
+}
+
+int uss725_reset(struct us_data *us)
+{
+        printk(KERN_CRIT "uss725 reset called\n");
+
+	/* We don't really have this feature. */
+	/* needed : reset device, init, wait busy,srst  */
+        return USS725_ERROR;
+}
+
diff -ruN linux-2.6.9.orig/drivers/usb/storage/uss725.h linux-2.6.9/drivers/usb/storage/uss725.h
--- linux-2.6.9.orig/drivers/usb/storage/uss725.h	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.9/drivers/usb/storage/uss725.h	2004-12-17 03:39:28.000000000 +0300
@@ -0,0 +1,32 @@
+/* Header File for In-System Design, Inc. USS725
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Nicolas Planel (nplanel@mandrakesoft.com)
+ *
+ * See uss725.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_USS725_H
+#define _USB_USS725_H
+
+extern int uss725_init(struct us_data *us);
+extern int uss725_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int uss725_reset(struct us_data *us);
+
+#endif
diff -ruN linux-2.6.9.orig/drivers/usb/storage/uss725_regs.h linux-2.6.9/drivers/usb/storage/uss725_regs.h
--- linux-2.6.9.orig/drivers/usb/storage/uss725_regs.h	1970-01-01 03:00:00.000000000 +0300
+++ linux-2.6.9/drivers/usb/storage/uss725_regs.h	2004-12-17 23:29:07.000000000 +0300
@@ -0,0 +1,163 @@
+/* Header File for In-System Design, Inc. USS725
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2002 Planel Nicolas (nplanel@mandrakesoft.com)
+ *
+ * See uss725.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_USS725_REGS_H
+#define _USB_USS725_REGS_H
+
+/*********************
+ ** sequencing info **
+ ********************/
+
+/* define general register addresses */
+#define REG_DATA 0x00
+#define REG_STAT 0x01
+#define REG_CTRL 0x02
+#define REG_EPPA 0x03
+#define REG_EPPD 0x04
+#define REG_ECPA 0x05
+#define REG_ECRR 0x06
+#define REG_CCTR 0x07
+#define REG_SETU 0x08
+#define REG_TIMO 0x09
+#define REG_ATAA 0x0A
+#define NUMBER_OF_REGS 0x0B
+
+/* define register addresses for read */
+#define REG_STAT_R 0x00
+#define REG_CTRL_R 0x01
+#define REG_ECRR_R 0x02
+#define REG_CCTR_R 0x03
+#define REG_DATA_R 0x04
+#define REG_EPPA_R 0x05
+#define REG_EPPD_R 0x05
+#define REG_SETU_R 0x06
+#define REG_TIMO_R 0x07
+#define REG_ATAA_R 0x08
+#define NUMBER_OF_REGS_R 0x09
+
+//
+// REG_STAT register definition
+//
+#define REG_STAT_PPORTBUSY_OR_IOCS16    (0x80)
+#define REG_STAT_PPORTACK_OR_IORDY      (0x40)
+#define REG_STAT_PPORTERR_OR_PDIAG      (0x20)
+#define REG_STAT_PPORTSEL_OR_INTRQ      (0x10)
+#define REG_STAT_PPORTFAULT_OR_DASP     (0x08)
+#define REG_STAT_1284_DISABLED          (0x04)
+#define REG_STAT_PPORTPLH_OR_DMARQ      (0x02)
+#define REG_STAT_EPP_TIMEOUT            (0x01)
+
+//
+// REG_SETU register definition
+//
+#define REG_SETU_HOLD_BULK              (0x80)
+#define REG_SETU_TERMINATION_WAIT       (0x40)
+#define REG_SETU_CLEAR_BULK_OUT         (0x20)
+#define REG_SETU_FORCE_NEGOTIATION      (0x10)
+#define REG_SETU_FORCE_COMPATIBILITY    (0x08)
+#define REG_SETU_AUTO_HTR               (0x04)
+#define REG_SETU_FILTER_SFT_OVERRIDE    (0x02)    
+#define REG_SETU_FILTER_ENABLE          (0x01)
+
+#define REG_SETU_STD                    (REG_SETU_HOLD_BULK|REG_SETU_FILTER_SFT_OVERRIDE)
+
+//
+// REG_CTRL register definition
+//
+#define REG_CTRL_PPORTHLH_RESET         (0x80)
+#define REG_CTRL_EPP_MASK               (0x40)
+#define REG_CTRL_DIRECTION_IN           (0x20) // else, is OUT
+#define REG_CTRL_INT_ENABLE             (0x10)
+#define REG_CTRL_PPORTSELECTIN_CSEL     (0x08)
+#define REG_CTRL_PPORTNINIT_DMACK       (0x04)
+#define REG_CTRL_PPORTAUTOFD_DIOR       (0x02)
+#define REG_CTRL_PPORTSTROBE_DIOW       (0x01)
+
+//
+// REG_ECCR register definition
+//
+#define REG_ECCR_MODE_STANDARD          (0x00)
+#define REG_ECCR_MODE_BIDIRECTIONAL     (0x20)
+#define REG_ECCR_MODE_COMPATIBILITY     (0x40)
+#define REG_ECCR_MODE_ECP               (0x60)
+#define REG_ECCR_MODE_EPP               (0x80)
+#define REG_ECCR_MODE_ATA               (0xE0)
+#define REG_ECCR_NACK_INTR              (0x10)
+#define REG_ECCR_NFAULT_INTR            (0x08)
+#define REG_ECCR_BULKIN_INTR            (0x04)
+#define REG_ECCR_BULKIN_EMPTY           (0x02)
+#define REG_ECCR_BULKOUT_EMPTY          (0x01)
+
+//
+// REG_CCTR register definition
+//
+#define REG_CCTR_MANUAL_REVERSE         (0x80)
+#define REG_CCTR_SLOW_RCCM              (0x40)
+#define REG_CCTR_SLOW_INSTRUCTION       (0x20)
+#define REG_CCTR_RETURN_ON_NO_DATA      (0x10)
+#define REG_CCTR_NFAULT_INT_MASK        (0x08)
+#define REG_CCTR_COMPRESS_ENABLE        (0x02)
+#define REG_CCTR_AUTO_MODE              (0x01)
+
+#define SEQ_RRMW 0x10
+#define SEQ_RRCM 0x20
+#define SEQ_RWRI 0xa0
+#define SEQ_RREN 0x30
+#define SEQ_WBIB 0x40
+#define SEQ_WBOB 0x50
+#define SEQ_DATI 0x60
+#define SEQ_DATO 0x70
+#define SEQ_EPPI 0x90
+#define SEQ_NOOP 0x80
+#define SEQ_SUBR 0xB0
+#define SEQ_RETN 0xB0
+#define SEQ_BLOCKING_BIT 0x80
+
+/* commands/requests */
+#define GET_DEVICE_ID		0 
+#define GET_PORT_STATUS		1 
+#define SOFT_RESET		2 
+#define GET_1284_REGISTER	3 
+#define SET_1284_REGISTER	4
+#define GET_SEQ_STATUS	 	5
+#define SEQ_LOAD		6
+#define SEQ_ABORT		7
+#define LOAD_EEPROM		8
+#define CLEAR_BUFFER	 	9
+
+// SEQUENCER_STATUS.statusBits
+#define SEQSTATUSF_ACTIVE                   0x80
+#define SEQSTATUSF_STOPPED                  0x40
+#define SEQSTATUSF_EXECUTING_SUBROUTINE     0x20
+
+struct seqstatus {
+    unsigned char seqPos;
+    unsigned char globalLoopCountHigh;
+    unsigned char globalLoopCountLow;
+    unsigned char statusFlags;
+    unsigned char instructLoopCountMid;
+    unsigned char instructLoopCountLow;
+};
+
+#endif
