See http://usbat2.sourceforge.net
Signed-off-by: Daniel Drake <[EMAIL PROTECTED]>
diff -urNpX dontdiff linux-2.6.10/drivers/usb/storage/Kconfig linux-dsd/drivers/usb/storage/Kconfig
--- linux-2.6.10/drivers/usb/storage/Kconfig 2005-01-24 22:25:54.000000000 +0000
+++ linux-dsd/drivers/usb/storage/Kconfig 2005-01-25 00:07:18.647253368 +0000
@@ -97,7 +97,18 @@ config USB_STORAGE_USBAT
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)"
diff -urNpX dontdiff linux-2.6.10/drivers/usb/storage/shuttle_usbat.c linux-dsd/drivers/usb/storage/shuttle_usbat.c
--- linux-2.6.10/drivers/usb/storage/shuttle_usbat.c 2005-01-24 21:54:15.000000000 +0000
+++ linux-dsd/drivers/usb/storage/shuttle_usbat.c 2005-01-25 00:02:27.609497832 +0000
@@ -4,10 +4,14 @@
*
* Current development and maintenance by:
* (c) 2000, 2001 Robert Baruch ([EMAIL PROTECTED])
+ * (c) 2004, 2005 Daniel Drake <[EMAIL PROTECTED]>
*
* Developed with the assistance of:
* (c) 2002 Alan Stern <[EMAIL PROTECTED]>
*
+ * Flash support based on earlier work by:
+ * (c) 2002 Thomas Kreiling <[EMAIL PROTECTED]>
+ *
* 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.
@@ -60,6 +64,31 @@
int transferred = 0;
/*
+ * 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,
@@ -149,6 +178,29 @@ static int usbat_get_status(struct us_da
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
@@ -522,8 +574,94 @@ static int usbat_multiple_write(struct u
if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- return usbat_wait_not_busy(us, 0);
+ 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
*/
@@ -563,6 +701,421 @@ static int usbat_write_user_io(struct us
}
/*
+ * 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
+ */
+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
*/
@@ -683,12 +1236,16 @@ static int usbat_select_and_test_registe
{
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 <= 0xB0; selector += 0x10) {
+ for (selector = 0xA0; selector <= max_selector; selector += 0x10) {
- if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
+ 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;
@@ -728,125 +1285,131 @@ static int usbat_select_and_test_registe
return USB_STOR_TRANSPORT_GOOD;
}
-int init_usbat_hp8200e(struct us_data *us)
+/*
+ * Initialize the USBAT processor and the storage device
+ */
+int init_usbat(struct us_data *us)
{
- int result;
+ 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;
- // Enable peripheral control signals
+ 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);
- if (usbat_write_user_io(us,
- USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ // 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);
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
US_DEBUGP("INIT 2\n");
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 3\n");
-
- // Reset peripheral, enable periph control signals
- // (bring reset signal up)
-
- if (usbat_write_user_io(us,
- USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 4\n");
-
- // Enable periph control signals
- // (bring reset signal down)
+ US_DEBUGP("INIT 3\n");
- if (usbat_write_user_io(us,
- USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ // 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 5\n");
+ US_DEBUGP("INIT 4\n");
- msleep(250);
+ if (usbat_get_device_type(us) == USBAT_DEV_HP8200) {
+ msleep(250);
- // Write 0x80 to ISA port 0x3F
+ // 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;
- if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ US_DEBUGP("INIT 5\n");
- US_DEBUGP("INIT 6\n");
+ // Read ISA port 0x27
+ rc = usbat_read(us, USBAT_ISA, 0x27, status);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
- // Read ISA port 0x27
+ US_DEBUGP("INIT 6\n");
- if (usbat_read(us, USBAT_ISA, 0x27, status) !=
- 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 7\n");
+ US_DEBUGP("INIT 7\n");
+ }
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ rc = usbat_select_and_test_registers(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
US_DEBUGP("INIT 8\n");
- if ( (result = usbat_select_and_test_registers(us)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 9\n");
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
+ // 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");
- // Enable periph control signals and card detect
-
- if (usbat_write_user_io(us,
- USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0,
- USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("INIT 11\n");
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
- return USB_STOR_TRANSPORT_ERROR;
-
- US_DEBUGP("INIT 12\n");
-
msleep(1400);
- if (usbat_read_user_io(us, status) !=
- USB_STOR_XFER_GOOD)
+ rc = usbat_read_user_io(us, status);
+ if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("INIT 13\n");
+ US_DEBUGP("INIT 12\n");
- if ( (result = usbat_select_and_test_registers(us)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
+ rc = usbat_select_and_test_registers(us);
+ if (rc != USB_STOR_TRANSPORT_GOOD)
+ return rc;
- US_DEBUGP("INIT 14\n");
+ US_DEBUGP("INIT 13\n");
- if (usbat_set_shuttle_features(us,
- 0x83, 0x00, 0x88, 0x08, 0x15, 0x14) !=
- USB_STOR_XFER_GOOD)
+ 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 15\n");
+ US_DEBUGP("INIT 14\n");
return USB_STOR_TRANSPORT_GOOD;
}
@@ -994,4 +1557,153 @@ int usbat_hp8200e_transport(struct scsi_
return result;
}
+/*
+ * Transport for USBAT02-based CompactFlash and similar storage devices
+ */
+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 -urNpX dontdiff linux-2.6.10/drivers/usb/storage/shuttle_usbat.h linux-dsd/drivers/usb/storage/shuttle_usbat.h
--- linux-2.6.10/drivers/usb/storage/shuttle_usbat.h 2005-01-24 22:51:32.000000000 +0000
+++ linux-dsd/drivers/usb/storage/shuttle_usbat.h 2005-01-25 00:01:52.425846560 +0000
@@ -5,8 +5,9 @@
*
* Current development and maintenance by:
* (c) 2000 Robert Baruch ([EMAIL PROTECTED])
+ * (c) 2004, 2005 Daniel Drake <[EMAIL PROTECTED]>
*
- * See scm.c for more explanation
+ * 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
@@ -26,6 +27,10 @@
#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
@@ -53,6 +58,14 @@
#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)
@@ -92,8 +105,23 @@
#define USBAT_FEAT_ET1 0x02
#define USBAT_FEAT_ET2 0x01
-/* HP 8200e stuff */
-extern int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
-extern int init_usbat_hp8200e(struct us_data *us);
+/* Transport functions */
+int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
+int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us);
+
+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 -urNpX dontdiff linux-2.6.10/drivers/usb/storage/unusual_devs.h linux-dsd/drivers/usb/storage/unusual_devs.h
--- linux-2.6.10/drivers/usb/storage/unusual_devs.h 2005-01-24 22:55:57.000000000 +0000
+++ linux-dsd/drivers/usb/storage/unusual_devs.h 2005-01-24 23:41:46.148228632 +0000
@@ -63,12 +63,12 @@ UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x
UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
- US_SC_8070, US_PR_SCM_ATAPI, init_usbat_hp8200e, 0),
+ 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_hp8200e, 0),
+ US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0),
#endif
/* Deduced by Jonathan Woithe <[EMAIL PROTECTED]>
@@ -253,7 +253,7 @@ UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x
UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999,
"SCM",
"SCM USBAT-02",
- US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat_hp8200e,
+ US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
US_FL_SINGLE_LUN),
#endif
@@ -565,6 +565,14 @@ UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x
US_FL_IGNORE_SER ),
#endif
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005,
+ "Sandisk",
+ "ImageMate SDDR-05b",
+ US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
+ US_FL_SINGLE_LUN),
+#endif
+
UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
"Sandisk",
"ImageMate SDDR-12",
diff -urNpX dontdiff linux-2.6.10/drivers/usb/storage/usb.c linux-dsd/drivers/usb/storage/usb.c
--- linux-2.6.10/drivers/usb/storage/usb.c 2005-01-24 21:22:57.000000000 +0000
+++ linux-dsd/drivers/usb/storage/usb.c 2005-01-24 23:42:31.066400032 +0000
@@ -573,7 +573,7 @@ static int get_transport(struct us_data
#ifdef CONFIG_USB_STORAGE_USBAT
case US_PR_SCM_ATAPI:
us->transport_name = "SCM/ATAPI";
- us->transport = usbat_hp8200e_transport;
+ us->transport = usbat_transport;
us->transport_reset = usb_stor_CB_reset;
us->max_lun = 1;
break;
--- linux-2.6.10/CREDITS 2004-12-24 21:35:23.000000000 +0000
+++ linux-dsd/CREDITS 2005-01-24 23:48:41.333110936 +0000
@@ -826,6 +826,11 @@ E: [EMAIL PROTECTED]
W: http://www.fsmlabs.com/linuxppcbk.html
D: PowerPC
+N: Daniel Drake
+E: [EMAIL PROTECTED]
+D: USBAT02 CompactFlash support in usb-storage
+S: UK
+
N: Oleg Drokin
E: [EMAIL PROTECTED]
W: http://www.ccssu.crimea.ua/~green
