aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/keucr
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/keucr')
-rw-r--r--drivers/staging/keucr/Kconfig14
-rw-r--r--drivers/staging/keucr/Makefile13
-rw-r--r--drivers/staging/keucr/TODO12
-rw-r--r--drivers/staging/keucr/common.h7
-rw-r--r--drivers/staging/keucr/init.c333
-rw-r--r--drivers/staging/keucr/init.h518
-rw-r--r--drivers/staging/keucr/scsiglue.c467
-rw-r--r--drivers/staging/keucr/scsiglue.h10
-rw-r--r--drivers/staging/keucr/smcommon.h29
-rw-r--r--drivers/staging/keucr/smil.h288
-rw-r--r--drivers/staging/keucr/smilecc.c211
-rw-r--r--drivers/staging/keucr/smilmain.c760
-rw-r--r--drivers/staging/keucr/smilsub.c679
-rw-r--r--drivers/staging/keucr/smscsi.c194
-rw-r--r--drivers/staging/keucr/transport.c865
-rw-r--r--drivers/staging/keucr/transport.h73
-rw-r--r--drivers/staging/keucr/usb.c642
-rw-r--r--drivers/staging/keucr/usb.h240
18 files changed, 5355 insertions, 0 deletions
diff --git a/drivers/staging/keucr/Kconfig b/drivers/staging/keucr/Kconfig
new file mode 100644
index 00000000000..ba756bf2066
--- /dev/null
+++ b/drivers/staging/keucr/Kconfig
@@ -0,0 +1,14 @@
+config USB_ENESTORAGE
+ tristate "USB ENE SM card reader support"
+ depends on USB && SCSI && m
+ ---help---
+ Say Y here if you wish to control a ENE SM Card reader.
+ To use SD/MS card, please build driver/usb/storage/ums-eneub6250.ko
+
+ This option depends on 'SCSI' support being enabled, but you
+ probably also need 'SCSI device support: SCSI disk support'
+ (BLK_DEV_SD) for most USB storage devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called keucr.
+
diff --git a/drivers/staging/keucr/Makefile b/drivers/staging/keucr/Makefile
new file mode 100644
index 00000000000..c180bf4fab9
--- /dev/null
+++ b/drivers/staging/keucr/Makefile
@@ -0,0 +1,13 @@
+ccflags-y := -Idrivers/scsi
+
+obj-$(CONFIG_USB_ENESTORAGE) += keucr.o
+
+keucr-y := \
+ usb.o \
+ scsiglue.o \
+ transport.o \
+ init.o \
+ smscsi.o \
+ smilmain.o \
+ smilsub.o \
+ smilecc.o
diff --git a/drivers/staging/keucr/TODO b/drivers/staging/keucr/TODO
new file mode 100644
index 00000000000..d6da656eee1
--- /dev/null
+++ b/drivers/staging/keucr/TODO
@@ -0,0 +1,12 @@
+TODO:
+ - checkpatch.pl clean
+ - sparse clean
+ - determine if the driver should not be using a duplicate
+ version of the usb-storage scsi interface code, but should
+ be merged into the drivers/usb/storage/ directory and
+ infrastructure instead.
+ - review by the USB developer community
+ - smcommon.h & smilsub.c: use kernel hweight8(), hweight16()
+
+Please send any patches for this driver to Al Cho <acho@novell.com> and
+Greg Kroah-Hartman <gregkh@linuxfoundation.org>.
diff --git a/drivers/staging/keucr/common.h b/drivers/staging/keucr/common.h
new file mode 100644
index 00000000000..f0b977616cd
--- /dev/null
+++ b/drivers/staging/keucr/common.h
@@ -0,0 +1,7 @@
+#ifndef COMMON_INCD
+#define COMMON_INCD
+
+#define BYTE_MASK 0xff
+
+#endif
+
diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c
new file mode 100644
index 00000000000..1e7449d6d12
--- /dev/null
+++ b/drivers/staging/keucr/init.c
@@ -0,0 +1,333 @@
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+#include "smil.h"
+#include "init.h"
+
+/*
+ * ENE_InitMedia():
+ */
+int ENE_InitMedia(struct us_data *us)
+{
+ int result;
+ u8 MiscReg03 = 0;
+
+ dev_info(&us->pusb_dev->dev, "--- Init Media ---\n");
+ result = ene_read_byte(us, REG_CARD_STATUS, &MiscReg03);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev, "Failed to read register\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ dev_info(&us->pusb_dev->dev, "MiscReg03 = %x\n", MiscReg03);
+
+ if (MiscReg03 & 0x02) {
+ if (!us->SM_Status.Ready && !us->MS_Status.Ready) {
+ result = ENE_SMInit(us);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ }
+ return result;
+}
+
+/*
+ * ene_read_byte() :
+ */
+int ene_read_byte(struct us_data *us, u16 index, void *buf)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x01;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xED;
+ bcb->CDB[2] = (u8)(index>>8);
+ bcb->CDB[3] = (u8)index;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
+ return result;
+}
+
+/*
+ *ENE_SMInit()
+ */
+int ENE_SMInit(struct us_data *us)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u8 buf[0x200];
+
+ dev_dbg(&us->pusb_dev->dev, "transport --- ENE_SMInit\n");
+
+ result = ENE_LoadBinCode(us, SM_INIT_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_info(&us->pusb_dev->dev,
+ "Failed to load SmartMedia init code\n: result= %x\n",
+ result);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x01;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia init code: result = %x\n",
+ result);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ us->SM_Status = *(struct keucr_sm_status *)&buf[0];
+
+ us->SM_DeviceID = buf[1];
+ us->SM_CardID = buf[2];
+
+ if (us->SM_Status.Insert && us->SM_Status.Ready) {
+ dev_info(&us->pusb_dev->dev, "Insert = %x\n",
+ us->SM_Status.Insert);
+ dev_info(&us->pusb_dev->dev, "Ready = %x\n",
+ us->SM_Status.Ready);
+ dev_info(&us->pusb_dev->dev, "WtP = %x\n",
+ us->SM_Status.WtP);
+ dev_info(&us->pusb_dev->dev, "DeviceID = %x\n",
+ us->SM_DeviceID);
+ dev_info(&us->pusb_dev->dev, "CardID = %x\n",
+ us->SM_CardID);
+ MediaChange = 1;
+ Check_D_MediaFmt(us);
+ } else {
+ dev_err(&us->pusb_dev->dev,
+ "SmartMedia Card Not Ready --- %x\n", buf[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * ENE_LoadBinCode()
+ */
+int ENE_LoadBinCode(struct us_data *us, u8 flag)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ /* void *buf; */
+ u8 *buf;
+
+ /* dev_info(&us->pusb_dev->dev, "transport --- ENE_LoadBinCode\n"); */
+ if (us->BIN_FLAG == flag)
+ return USB_STOR_TRANSPORT_GOOD;
+
+ buf = kmalloc(0x800, GFP_KERNEL);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ switch (flag) {
+ /* For SS */
+ case SM_INIT_PATTERN:
+ dev_dbg(&us->pusb_dev->dev, "SM_INIT_PATTERN\n");
+ memcpy(buf, SM_Init, 0x800);
+ break;
+ case SM_RW_PATTERN:
+ dev_dbg(&us->pusb_dev->dev, "SM_RW_PATTERN\n");
+ memcpy(buf, SM_Rdwr, 0x800);
+ break;
+ }
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x800;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xEF;
+
+ result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
+
+ kfree(buf);
+ us->BIN_FLAG = flag;
+ return result;
+}
+
+/*
+ * ENE_SendScsiCmd():
+ */
+int ENE_SendScsiCmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+
+ int result;
+ unsigned int transfer_length = bcb->DataTransferLength,
+ cswlen = 0, partial = 0;
+ unsigned int residue;
+
+ /* dev_dbg(&us->pusb_dev->dev, "transport --- ENE_SendScsiCmd\n"); */
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, US_BULK_CB_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "send cmd to out endpoint fail ---\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (buf) {
+ unsigned int pipe = fDir;
+
+ if (fDir == FDIR_READ)
+ pipe = us->recv_bulk_pipe;
+ else
+ pipe = us->send_bulk_pipe;
+
+ /* Bulk */
+ if (use_sg)
+ result = usb_stor_bulk_srb(us, pipe, us->srb);
+ else
+ result = usb_stor_bulk_transfer_sg(us, pipe, buf,
+ transfer_length, 0, &partial);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev, "data transfer fail ---\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen);
+
+ if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+ dev_warn(&us->pusb_dev->dev,
+ "Received 0-length CSW; retrying...\n");
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, &cswlen);
+ }
+
+ if (result == USB_STOR_XFER_STALLED) {
+ /* get the status again */
+ dev_warn(&us->pusb_dev->dev,
+ "Attempting to get CSW (2nd try)...\n");
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ bcs, US_BULK_CS_WRAP_LEN, NULL);
+ }
+
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* check bulk status */
+ residue = le32_to_cpu(bcs->Residue);
+
+ /*
+ * try to compute the actual residue, based on how much data
+ * was really transferred and what the device tells us
+ */
+ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
+ residue = min(residue, transfer_length);
+ if (us->srb)
+ scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
+ (int) residue));
+ }
+
+ if (bcs->Status != US_BULK_STAT_OK)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * ENE_Read_Data()
+ */
+int ENE_Read_Data(struct us_data *us, void *buf, unsigned int length)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+ int result;
+
+ /* dev_dbg(&us->pusb_dev->dev, "transport --- ENE_Read_Data\n"); */
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = length;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xED;
+ bcb->CDB[2] = 0xFF;
+ bcb->CDB[3] = 0x81;
+
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
+ US_BULK_CB_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* R/W data */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ buf, length, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+ if (bcs->Status != US_BULK_STAT_OK)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/*
+ * ENE_Write_Data():
+ */
+int ENE_Write_Data(struct us_data *us, void *buf, unsigned int length)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+ int result;
+
+ /* printk("transport --- ENE_Write_Data\n"); */
+ /* set up the command wrapper */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = length;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xEE;
+ bcb->CDB[2] = 0xFF;
+ bcb->CDB[3] = 0x81;
+
+ /* send cmd to out endpoint */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
+ US_BULK_CB_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* R/W data */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ buf, length, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* Get CSW for device status */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, NULL);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+ if (bcs->Status != US_BULK_STAT_OK)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
diff --git a/drivers/staging/keucr/init.h b/drivers/staging/keucr/init.h
new file mode 100644
index 00000000000..d1367e726ff
--- /dev/null
+++ b/drivers/staging/keucr/init.h
@@ -0,0 +1,518 @@
+#include "common.h"
+
+static u8 SM_Init[] = {
+0x7B, 0x09, 0x7C, 0xF0, 0x7D, 0x10, 0x7E, 0xE9,
+0x7F, 0xCC, 0x12, 0x2F, 0x71, 0x90, 0xE9, 0xCC,
+0xE0, 0xB4, 0x07, 0x12, 0x90, 0xFF, 0x09, 0xE0,
+0x30, 0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74, 0x80,
+0xF0, 0x12, 0x2F, 0x5C, 0xD3, 0x22, 0x78, 0x00,
+0x90, 0xFF, 0x83, 0xE0, 0xA2, 0xE1, 0x92, 0x0A,
+0x20, 0x0A, 0x03, 0x02, 0xE0, 0xD0, 0x7F, 0x00,
+0x12, 0x2F, 0xCB, 0x20, 0x01, 0x05, 0xC2, 0x25,
+0x02, 0xE0, 0xEB, 0xC3, 0xE8, 0x94, 0x02, 0x40,
+0x03, 0x02, 0xE0, 0xD0, 0xC0, 0x00, 0x90, 0xFE,
+0x66, 0x74, 0x90, 0xF0, 0x12, 0xE1, 0x40, 0x90,
+0xFF, 0x95, 0xE0, 0xC2, 0xE4, 0xF0, 0x90, 0xFF,
+0x97, 0x74, 0x01, 0xF0, 0x7E, 0x01, 0x7F, 0x90,
+0x12, 0x2F, 0x74, 0x90, 0xFF, 0x97, 0x74, 0x03,
+0xF0, 0x90, 0xFE, 0xC5, 0xE4, 0xF0, 0x74, 0x00,
+0x90, 0xFE, 0x6A, 0xF0, 0xA3, 0xF0, 0xA3, 0xF0,
+0xA3, 0xF0, 0x7E, 0x23, 0x7F, 0xDC, 0x12, 0x2F,
+0x74, 0x12, 0x2F, 0x5C, 0x90, 0xFE, 0x64, 0xE0,
+0x54, 0x01, 0x60, 0x04, 0xD2, 0x02, 0x80, 0x02,
+0xC2, 0x02, 0x90, 0xFF, 0x95, 0xE0, 0xD2, 0xE4,
+0xF0, 0x78, 0x10, 0x79, 0x04, 0x12, 0xE1, 0x71,
+0x50, 0x3A, 0x90, 0xE9, 0xC6, 0xE0, 0x90, 0xE9,
+0xC3, 0xF0, 0x78, 0x9A, 0x79, 0x04, 0x12, 0xE1,
+0x71, 0x50, 0x29, 0x90, 0xE9, 0xC7, 0xE0, 0xB4,
+0xB5, 0x22, 0x90, 0xE9, 0xC4, 0xF0, 0xD0, 0x00,
+0xD2, 0x00, 0xC2, 0x01, 0xC2, 0x25, 0x80, 0x1B,
+0xC2, 0x00, 0xD2, 0x01, 0x74, 0xFF, 0x90, 0xE9,
+0xC3, 0xF0, 0xA3, 0xF0, 0x51, 0x01, 0xC2, 0x0A,
+0xC2, 0x02, 0x80, 0x07, 0xD0, 0x00, 0x05, 0x00,
+0x02, 0xE0, 0x43, 0x90, 0xFF, 0x09, 0xE0, 0x30,
+0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74, 0x80, 0xF0,
+0x90, 0xFF, 0x09, 0xE0, 0x30, 0xE5, 0xFC, 0xE4,
+0xA2, 0x0A, 0x92, 0xE0, 0xA2, 0x00, 0x92, 0xE1,
+0xA2, 0x01, 0x92, 0xE2, 0xA2, 0x02, 0x92, 0xE6,
+0xA2, 0x25, 0x92, 0xE7, 0x90, 0xF4, 0x00, 0xF0,
+0x90, 0xE9, 0xC3, 0xE0, 0x90, 0xF4, 0x01, 0xF0,
+0x90, 0xE9, 0xC4, 0xE0, 0x90, 0xF4, 0x02, 0xF0,
+0x90, 0xFF, 0x2A, 0x74, 0x02, 0xF0, 0xA3, 0x74,
+0x00, 0xF0, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00,
+0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22,
+0x90, 0xFE, 0x71, 0xE4, 0xF0, 0x90, 0xFE, 0x72,
+0x74, 0x01, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0x0C,
+0xF0, 0x90, 0xFE, 0x64, 0x74, 0x00, 0x45, 0x4E,
+0xF0, 0x90, 0xFE, 0x64, 0xE0, 0x54, 0x10, 0x60,
+0x08, 0x90, 0xFE, 0x72, 0x74, 0x81, 0xF0, 0xD3,
+0x22, 0x90, 0xFE, 0x64, 0x74, 0x08, 0xF0, 0xC3,
+0x22, 0x90, 0xFE, 0x6F, 0xE9, 0x14, 0xF0, 0x90,
+0xFE, 0x70, 0xE0, 0x54, 0xFC, 0xF0, 0x90, 0xFE,
+0x68, 0x74, 0x00, 0xF0, 0xB8, 0x9A, 0x2A, 0x74,
+0x15, 0x90, 0xFE, 0x64, 0xF0, 0x74, 0x9A, 0x90,
+0xFE, 0x60, 0xF0, 0x74, 0x16, 0x90, 0xFE, 0x64,
+0xF0, 0x74, 0x00, 0x90, 0xFE, 0x60, 0xF0, 0x30,
+0x0A, 0x5D, 0x90, 0xFE, 0x64, 0xE0, 0x20, 0xE7,
+0xF6, 0x74, 0x14, 0x90, 0xFE, 0x64, 0xF0, 0x80,
+0x20, 0x90, 0xFE, 0x6E, 0xE8, 0x44, 0x01, 0xF0,
+0xC2, 0x09, 0x12, 0xE3, 0x26, 0x20, 0x08, 0x0E,
+0x12, 0xE3, 0x32, 0x30, 0x3E, 0xF7, 0x90, 0xFE,
+0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09, 0x20, 0x09,
+0x2E, 0x7A, 0xE9, 0x7B, 0xC5, 0x7C, 0xFE, 0x7D,
+0x60, 0xB8, 0x10, 0x07, 0x90, 0xFE, 0x69, 0xE0,
+0x20, 0xE6, 0xFC, 0x8C, 0x83, 0x8D, 0x82, 0xE0,
+0x8A, 0x83, 0x8B, 0x82, 0xF0, 0xA3, 0xAA, 0x83,
+0xAB, 0x82, 0xD9, 0xE5, 0xB8, 0x9A, 0x06, 0x74,
+0x10, 0x90, 0xFE, 0x64, 0xF0, 0xD3, 0x22, 0xC3,
+0x22, 0x90, 0xFF, 0x83, 0xE0, 0xA2, 0xE1, 0x92,
+0x25, 0x20, 0x25, 0x06, 0xC2, 0x1F, 0xD2, 0x19,
+0xC3, 0x22, 0x7F, 0x02, 0x12, 0x2F, 0xCB, 0x20,
+0x19, 0x05, 0x30, 0x1F, 0x02, 0xD3, 0x22, 0x90,
+0xEA, 0x44, 0x74, 0x80, 0xF0, 0x7F, 0x10, 0x12,
+0x2F, 0xC5, 0x90, 0xFE, 0x47, 0xE0, 0x44, 0x80,
+0xF0, 0x78, 0x00, 0xE8, 0xC3, 0x94, 0x04, 0x50,
+0x0A, 0x7F, 0x88, 0x7E, 0x13, 0x12, 0xE3, 0x4D,
+0x08, 0x80, 0xF0, 0x90, 0xFE, 0x45, 0xE0, 0x54,
+0xFB, 0xF0, 0x90, 0xFE, 0x47, 0xE0, 0x54, 0xBF,
+0xF0, 0x90, 0xFE, 0x45, 0xE0, 0x54, 0xFE, 0xF0,
+0x90, 0xFE, 0x45, 0xE0, 0x54, 0x7F, 0xF0, 0x90,
+0xFE, 0x46, 0xE0, 0x44, 0x40, 0xF0, 0x90, 0xFE,
+0x45, 0xE0, 0x54, 0xC7, 0x44, 0x18, 0xF0, 0x90,
+0xFE, 0x47, 0xE0, 0x44, 0x08, 0xF0, 0x90, 0xFE,
+0x45, 0xE0, 0x44, 0x40, 0xF0, 0x7F, 0x32, 0x7E,
+0x00, 0x12, 0xE3, 0x4D, 0x90, 0xFE, 0x51, 0xE0,
+0x54, 0x33, 0xF0, 0x90, 0xFE, 0x44, 0x74, 0x02,
+0xF0, 0x30, 0x25, 0x04, 0xE0, 0x20, 0xE1, 0xF9,
+0x90, 0xFE, 0x51, 0xE0, 0x54, 0x0F, 0xF0, 0x90,
+0xFE, 0x44, 0x74, 0x02, 0xF0, 0x30, 0x25, 0x04,
+0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xFE, 0x44, 0x74,
+0x04, 0xF0, 0x30, 0x25, 0x04, 0xE0, 0x20, 0xE2,
+0xF9, 0x90, 0xFE, 0x4C, 0xE0, 0xF0, 0x90, 0xFE,
+0x4D, 0xE0, 0xF0, 0x90, 0xFE, 0x48, 0x74, 0x7F,
+0xF0, 0x90, 0xFE, 0x49, 0x74, 0x9F, 0xF0, 0x90,
+0xFE, 0x51, 0xE0, 0x54, 0x3C, 0x44, 0x02, 0xF0,
+0x90, 0xFE, 0x44, 0x74, 0x02, 0xF0, 0x30, 0x25,
+0x04, 0xE0, 0x20, 0xE1, 0xF9, 0x90, 0xFE, 0x46,
+0xE0, 0x44, 0x20, 0xF0, 0x79, 0x02, 0x7A, 0x06,
+0x7B, 0x00, 0x7C, 0x00, 0x7D, 0x06, 0x7E, 0xEB,
+0x7F, 0xC9, 0x12, 0x2F, 0xA7, 0x40, 0x03, 0x02,
+0xE3, 0x04, 0xD3, 0x22, 0xE4, 0x90, 0xFE, 0x48,
+0xF0, 0x90, 0xFE, 0x49, 0xF0, 0x90, 0xFE, 0x4C,
+0xE0, 0xF0, 0x90, 0xFE, 0x4D, 0xE0, 0xF0, 0x90,
+0xFE, 0x47, 0xE0, 0x54, 0x7F, 0xF0, 0xC2, 0x25,
+0xC2, 0x1F, 0xD2, 0x19, 0xC3, 0x22, 0xC2, 0x3E,
+0x75, 0x7C, 0x00, 0x75, 0x7D, 0x00, 0x75, 0x7E,
+0x00, 0x22, 0x05, 0x7C, 0xE5, 0x7C, 0x70, 0x14,
+0x05, 0x7D, 0xE5, 0x7D, 0x70, 0x04, 0x05, 0x7E,
+0x80, 0x0A, 0xB4, 0x17, 0x07, 0xE5, 0x7E, 0xB4,
+0x06, 0x02, 0xD2, 0x3E, 0x22, 0x75, 0x8A, 0x00,
+0x75, 0x8C, 0xCE, 0xC2, 0x8D, 0x90, 0xEA, 0x65,
+0xE4, 0xF0, 0xA3, 0xF0, 0xD2, 0x8C, 0x90, 0xEA,
+0x65, 0xE0, 0xFC, 0xA3, 0xE0, 0xFD, 0xEC, 0xC3,
+0x9E, 0x40, 0xF3, 0x70, 0x05, 0xED, 0xC3, 0x9F,
+0x40, 0xEC, 0xC2, 0x8C, 0x22, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x58, 0x44, 0x2D, 0x49, 0x6E, 0x69, 0x74, 0x20,
+0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x31 };
+
+static u8 SM_Rdwr[] = {
+0x7B, 0x0C, 0x7C, 0xF0, 0x7D, 0x10, 0x7E, 0xE9,
+0x7F, 0xCC, 0x12, 0x2F, 0x71, 0x90, 0xE9, 0xC3,
+0xE0, 0xB4, 0x73, 0x04, 0x74, 0x40, 0x80, 0x09,
+0xB4, 0x75, 0x04, 0x74, 0x40, 0x80, 0x02, 0x74,
+0xC0, 0x90, 0xFE, 0x70, 0xF0, 0x90, 0xFF, 0x09,
+0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF, 0x23, 0x74,
+0x80, 0xF0, 0x90, 0xFF, 0x83, 0xE0, 0xA2, 0xE1,
+0x92, 0x0A, 0x40, 0x01, 0x22, 0x90, 0xFE, 0x6A,
+0xE4, 0xF0, 0x90, 0xE9, 0xCC, 0xE0, 0xB4, 0x02,
+0x05, 0xD2, 0x06, 0x02, 0xE0, 0x78, 0xB4, 0x03,
+0x03, 0x02, 0xE3, 0xD0, 0xB4, 0x04, 0x03, 0x02,
+0xE1, 0xC6, 0xB4, 0x05, 0x03, 0x02, 0xE5, 0x20,
+0xB4, 0x06, 0x03, 0x02, 0xE5, 0xE0, 0xB4, 0x07,
+0x05, 0x12, 0x2F, 0x5C, 0xD3, 0x22, 0xB4, 0x08,
+0x05, 0xC2, 0x06, 0x02, 0xE6, 0x3B, 0xC3, 0x22,
+0xE5, 0x3E, 0xC3, 0x13, 0x90, 0xE9, 0xCA, 0xF0,
+0xC0, 0xE0, 0x75, 0xF0, 0x02, 0xC0, 0xF0, 0x12,
+0xE0, 0xD8, 0xEF, 0x70, 0x21, 0x20, 0x37, 0x07,
+0x20, 0x09, 0x04, 0xD0, 0xF0, 0x80, 0x05, 0xD0,
+0xF0, 0xD5, 0xF0, 0xE9, 0xD0, 0xE0, 0x90, 0xFF,
+0x28, 0xE0, 0x30, 0xE7, 0xFC, 0x90, 0xFF, 0x28,
+0xE0, 0x44, 0x01, 0xF0, 0xC3, 0x22, 0xD0, 0xF0,
+0x90, 0xE9, 0xCF, 0xE0, 0x24, 0x01, 0xF0, 0x90,
+0xE9, 0xCE, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9,
+0xCD, 0xE0, 0x34, 0x00, 0xF0, 0xD0, 0xE0, 0x14,
+0x70, 0xB6, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00,
+0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22,
+0xC2, 0x08, 0xC2, 0x36, 0xC2, 0x37, 0xE4, 0x90,
+0xEB, 0xC2, 0xF0, 0x90, 0xE9, 0xCD, 0xE0, 0xF8,
+0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0x90, 0xFE, 0x6B,
+0xF0, 0xA3, 0xE9, 0xF0, 0xA3, 0xE8, 0xF0, 0x90,
+0xFE, 0x6F, 0x74, 0x0F, 0xF0, 0x90, 0xFE, 0x70,
+0xE0, 0x54, 0xFC, 0x44, 0x02, 0xF0, 0x90, 0xFE,
+0xC6, 0x74, 0x02, 0xF0, 0xA3, 0x74, 0x0F, 0xF0,
+0x90, 0xFE, 0xC0, 0x74, 0xF4, 0xF0, 0x74, 0x00,
+0xA3, 0xF0, 0x90, 0xFE, 0x68, 0x74, 0x21, 0xF0,
+0x90, 0xFE, 0x64, 0x74, 0x70, 0x45, 0x4E, 0xF0,
+0x90, 0xFE, 0x64, 0x74, 0x30, 0x45, 0x4E, 0xF0,
+0x30, 0x06, 0x07, 0x90, 0xFF, 0x09, 0xE0, 0x30,
+0xE5, 0xFC, 0x90, 0xFE, 0x6E, 0x74, 0x51, 0xF0,
+0x90, 0xFE, 0xC4, 0x74, 0x21, 0xF0, 0xC2, 0x09,
+0x12, 0xE7, 0xB0, 0x20, 0x08, 0x0E, 0x12, 0xE7,
+0xBC, 0x30, 0x3E, 0xF7, 0x90, 0xFE, 0xD8, 0x74,
+0x01, 0xF0, 0xD2, 0x09, 0x30, 0x09, 0x03, 0x7F,
+0x00, 0x22, 0x12, 0xE7, 0xB0, 0x20, 0x36, 0x11,
+0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC, 0x30, 0x3E,
+0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0, 0xD2,
+0x37, 0x30, 0x37, 0x03, 0x7F, 0x00, 0x22, 0x90,
+0xFE, 0x64, 0x74, 0x10, 0x45, 0x4E, 0xF0, 0x90,
+0xFE, 0x64, 0x74, 0x00, 0x45, 0x4E, 0xF0, 0x12,
+0x2F, 0x65, 0x12, 0x2F, 0x68, 0xBF, 0x00, 0x09,
+0x74, 0x02, 0x90, 0xEB, 0xC2, 0xF0, 0x7F, 0x00,
+0x22, 0x12, 0x2F, 0x6B, 0xBF, 0x00, 0x0F, 0x12,
+0x2F, 0x6E, 0xBF, 0x00, 0x09, 0x74, 0x01, 0x90,
+0xEB, 0xC2, 0xF0, 0x7F, 0x00, 0x22, 0x30, 0x06,
+0x0A, 0x90, 0xFF, 0x2A, 0x74, 0x02, 0xF0, 0xA3,
+0x74, 0x00, 0xF0, 0x7F, 0x01, 0x22, 0x12, 0xE3,
+0xAA, 0x74, 0x01, 0x90, 0xE9, 0xCB, 0xF0, 0xE5,
+0x3E, 0xC3, 0x13, 0x90, 0xE9, 0xCA, 0xF0, 0xC0,
+0xE0, 0x75, 0xF0, 0x02, 0xC0, 0xF0, 0x12, 0xE2,
+0x2F, 0xEF, 0x70, 0x21, 0x20, 0x37, 0x07, 0x20,
+0x09, 0x04, 0xD0, 0xF0, 0x80, 0x05, 0xD0, 0xF0,
+0xD5, 0xF0, 0xE9, 0xD0, 0xE0, 0x90, 0xFF, 0x28,
+0xE0, 0x30, 0xE7, 0xFC, 0x90, 0xFF, 0x28, 0xE0,
+0x44, 0x01, 0xF0, 0xC3, 0x22, 0xD0, 0xF0, 0x90,
+0xE9, 0xD2, 0xE0, 0x24, 0x01, 0xF0, 0x90, 0xE9,
+0xD1, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9, 0xD0,
+0xE0, 0x34, 0x00, 0xF0, 0xD0, 0xE0, 0x14, 0x70,
+0xB6, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00, 0x75,
+0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22, 0xC2,
+0x08, 0xC2, 0x36, 0xC2, 0x37, 0x90, 0xFE, 0x68,
+0x74, 0x31, 0xF0, 0x90, 0xE9, 0xD0, 0xE0, 0xF8,
+0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0x90, 0xFE, 0x6B,
+0xF0, 0xA3, 0xE9, 0xF0, 0xA3, 0xE8, 0xF0, 0x90,
+0xFE, 0x6F, 0x74, 0x0F, 0xF0, 0x90, 0xFE, 0x70,
+0xE0, 0x54, 0xFC, 0x44, 0x22, 0xF0, 0x90, 0xE9,
+0xCB, 0xE0, 0x70, 0x0C, 0x90, 0xFE, 0xC0, 0x74,
+0xF4, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x80, 0x0A,
+0x90, 0xFE, 0xC0, 0x74, 0xF0, 0xF0, 0xA3, 0x74,
+0x00, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0xF0, 0x45,
+0x4E, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0xB0, 0x45,
+0x4E, 0xF0, 0x90, 0xFE, 0x6E, 0x74, 0x81, 0xF0,
+0x90, 0xE9, 0xCB, 0xE0, 0x70, 0x0D, 0x90, 0xFE,
+0xC6, 0x74, 0x02, 0xF0, 0xA3, 0x74, 0x0F, 0xF0,
+0x02, 0xE3, 0x56, 0x20, 0x2D, 0x03, 0x02, 0xE2,
+0xEF, 0x90, 0xFE, 0xC6, 0x74, 0x01, 0xF0, 0xA3,
+0x74, 0xFF, 0xF0, 0x90, 0xFF, 0x09, 0x30, 0x0A,
+0x04, 0xE0, 0x30, 0xE1, 0xF9, 0x90, 0xFE, 0xC4,
+0x74, 0x23, 0xF0, 0x12, 0xE7, 0xB0, 0x20, 0x36,
+0x11, 0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC, 0x30,
+0x3E, 0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0,
+0xD2, 0x37, 0x30, 0x37, 0x02, 0x61, 0xA7, 0x90,
+0xFF, 0x09, 0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF,
+0x23, 0x74, 0x80, 0xF0, 0x02, 0xE3, 0x3F, 0x90,
+0xFE, 0xC6, 0xE4, 0xF0, 0xA3, 0x74, 0x3F, 0xF0,
+0x78, 0x08, 0xC0, 0x00, 0xC2, 0x36, 0xC2, 0x37,
+0x90, 0xFF, 0x09, 0x30, 0x0A, 0x04, 0xE0, 0x30,
+0xE1, 0xF9, 0x90, 0xFE, 0xC4, 0x74, 0x23, 0xF0,
+0x12, 0xE7, 0xB0, 0x20, 0x36, 0x11, 0x20, 0x37,
+0x0E, 0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF4, 0x90,
+0xFE, 0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x37, 0x90,
+0xFF, 0x09, 0xE0, 0x30, 0xE1, 0x06, 0x90, 0xFF,
+0x23, 0x74, 0x80, 0xF0, 0x30, 0x37, 0x04, 0xD0,
+0x00, 0x80, 0x6C, 0xD0, 0x00, 0xD8, 0xBB, 0xC2,
+0x36, 0xC2, 0x37, 0x90, 0xFE, 0xC6, 0xE4, 0xF0,
+0xA3, 0x74, 0x0F, 0xF0, 0x90, 0xFE, 0xC0, 0x74,
+0xF6, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x90, 0xFE,
+0xC4, 0x74, 0x23, 0xF0, 0x12, 0xE7, 0xB0, 0x20,
+0x36, 0x11, 0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC,
+0x30, 0x3E, 0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01,
+0xF0, 0xD2, 0x37, 0x30, 0x37, 0x02, 0x80, 0x2F,
+0xC2, 0x09, 0x12, 0xE7, 0xB0, 0x20, 0x08, 0x0E,
+0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF7, 0x90, 0xFE,
+0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09, 0x30, 0x09,
+0x02, 0x80, 0x14, 0x90, 0xFE, 0x64, 0x74, 0x90,
+0x45, 0x4E, 0xF0, 0x90, 0xFE, 0x64, 0x74, 0x80,
+0x45, 0x4E, 0xF0, 0x12, 0x2F, 0x59, 0x22, 0x7F,
+0x00, 0x22, 0x90, 0xF6, 0x00, 0x7F, 0x06, 0x74,
+0xFF, 0xF0, 0xA3, 0xDF, 0xFC, 0x7B, 0x02, 0x7C,
+0xE9, 0x7D, 0xD3, 0x7E, 0xF6, 0x7F, 0x06, 0x12,
+0x2F, 0x71, 0x7B, 0x02, 0x7C, 0xE9, 0x7D, 0xD3,
+0x7E, 0xF6, 0x7F, 0x0B, 0x12, 0x2F, 0x71, 0x22,
+0x90, 0xFE, 0xC6, 0xE4, 0xF0, 0xA3, 0x74, 0x0F,
+0xF0, 0x90, 0xFE, 0x6F, 0xF0, 0x90, 0xFE, 0x70,
+0xE0, 0x54, 0xFC, 0xF0, 0x90, 0xFE, 0xC0, 0x74,
+0xF6, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x90, 0xFE,
+0x68, 0x74, 0x21, 0xF0, 0x90, 0xFE, 0x66, 0xE0,
+0x54, 0xEF, 0xF0, 0x90, 0xE9, 0xD3, 0xE0, 0xF5,
+0x08, 0xA3, 0xE0, 0xF5, 0x09, 0x90, 0xFF, 0x09,
+0xE0, 0x30, 0xE5, 0xFC, 0xE4, 0xF5, 0x10, 0x7E,
+0xF4, 0x7F, 0x00, 0xC0, 0x06, 0xC0, 0x07, 0xC2,
+0x36, 0xC2, 0x37, 0xC2, 0x09, 0x90, 0xE9, 0xCD,
+0xE0, 0xF8, 0xA3, 0xE0, 0xF9, 0xA3, 0xE0, 0x90,
+0xFE, 0x6B, 0xF0, 0xA3, 0xE9, 0xF0, 0xA3, 0xE8,
+0xF0, 0x90, 0xFE, 0x6E, 0x74, 0x71, 0xF0, 0x90,
+0xFE, 0xC4, 0x74, 0x21, 0xF0, 0x90, 0xFE, 0x65,
+0x12, 0xE7, 0xB0, 0xE0, 0x20, 0xE4, 0x11, 0x12,
+0xE7, 0xBC, 0x30, 0x3E, 0xF6, 0x90, 0xFE, 0xD8,
+0x74, 0x01, 0xF0, 0xD2, 0x09, 0x02, 0xE4, 0x72,
+0x74, 0x10, 0xF0, 0x12, 0xE7, 0xB0, 0x20, 0x36,
+0x11, 0x20, 0x37, 0x0E, 0x12, 0xE7, 0xBC, 0x30,
+0x3E, 0xF4, 0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0,
+0xD2, 0x37, 0x20, 0x09, 0x05, 0x20, 0x37, 0x02,
+0x80, 0x10, 0x90, 0xFE, 0x66, 0xE0, 0x44, 0x10,
+0xF0, 0x12, 0x2F, 0x5C, 0xD0, 0x07, 0xD0, 0x06,
+0xC3, 0x22, 0xD0, 0x07, 0xD0, 0x06, 0x7B, 0x10,
+0x7C, 0xF6, 0x7D, 0x00, 0x12, 0x2F, 0x71, 0x05,
+0x10, 0xC3, 0xE5, 0x09, 0x94, 0x01, 0xF5, 0x09,
+0xE5, 0x08, 0x94, 0x00, 0xF5, 0x08, 0x45, 0x09,
+0x70, 0x03, 0x02, 0xE4, 0xEF, 0x90, 0xE9, 0xCF,
+0xE0, 0x24, 0x20, 0xF0, 0x90, 0xE9, 0xCE, 0xE0,
+0x34, 0x00, 0xF0, 0x90, 0xE9, 0xCD, 0xE0, 0x34,
+0x00, 0xF0, 0xC3, 0xEF, 0x24, 0x10, 0xFF, 0xEE,
+0x34, 0x00, 0xFE, 0xE5, 0x10, 0x64, 0x20, 0x60,
+0x03, 0x02, 0xE4, 0x13, 0x90, 0xFF, 0x2A, 0x74,
+0x02, 0xF0, 0xA3, 0x74, 0x00, 0xF0, 0x75, 0x10,
+0x00, 0x7E, 0xF4, 0x7F, 0x00, 0x90, 0xFF, 0x09,
+0xE0, 0x30, 0xE5, 0xFC, 0x02, 0xE4, 0x13, 0xE5,
+0x10, 0x60, 0x17, 0x7E, 0x00, 0x7F, 0x00, 0x78,
+0x04, 0xC3, 0x33, 0xFF, 0xEE, 0x33, 0xFE, 0xEF,
+0xD8, 0xF8, 0x90, 0xFF, 0x2A, 0xEE, 0xF0, 0xA3,
+0xEF, 0xF0, 0x90, 0xFE, 0x66, 0xE0, 0x44, 0x10,
+0xF0, 0x12, 0x2F, 0x5C, 0x78, 0x00, 0x88, 0x3C,
+0x88, 0x3D, 0x88, 0x3E, 0x88, 0x3F, 0xD3, 0x22,
+0x12, 0x2F, 0x5F, 0x12, 0x2F, 0x62, 0x90, 0xFE,
+0xC6, 0xE4, 0xF0, 0xA3, 0x74, 0x0F, 0xF0, 0x90,
+0xFE, 0x6F, 0xF0, 0x90, 0xFE, 0x70, 0xE0, 0x54,
+0xFC, 0xF0, 0x90, 0xFE, 0xC0, 0x74, 0xF6, 0xF0,
+0xA3, 0x74, 0x00, 0xF0, 0x90, 0xFE, 0x68, 0x74,
+0x31, 0xF0, 0x90, 0xE9, 0xD3, 0xE0, 0xF8, 0xC0,
+0x00, 0xC2, 0x08, 0xC2, 0x36, 0xC2, 0x37, 0x90,
+0xE9, 0xD0, 0xE0, 0xF8, 0xA3, 0xE0, 0xF9, 0xA3,
+0xE0, 0x90, 0xFE, 0x6B, 0xF0, 0xA3, 0xE9, 0xF0,
+0xA3, 0xE8, 0xF0, 0x90, 0xFE, 0x6E, 0x74, 0x81,
+0xF0, 0x90, 0xFE, 0xC4, 0x74, 0x23, 0xF0, 0x12,
+0xE7, 0xB0, 0x20, 0x36, 0x11, 0x20, 0x37, 0x0E,
+0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF4, 0x90, 0xFE,
+0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x37, 0x30, 0x37,
+0x07, 0xD0, 0x00, 0x12, 0x2F, 0x5C, 0xC3, 0x22,
+0xC2, 0x09, 0x12, 0xE7, 0xB0, 0x20, 0x08, 0x0E,
+0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF7, 0x90, 0xFE,
+0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09, 0x20, 0x09,
+0xE0, 0x90, 0xE9, 0xD2, 0xE0, 0x24, 0x01, 0xF0,
+0x90, 0xE9, 0xD1, 0xE0, 0x34, 0x00, 0xF0, 0x90,
+0xE9, 0xD0, 0xE0, 0x34, 0x00, 0xF0, 0xD0, 0x00,
+0x18, 0xE8, 0x60, 0x03, 0x02, 0xE5, 0x4F, 0x12,
+0x2F, 0x5C, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00,
+0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22,
+0x90, 0xE9, 0xD0, 0xE0, 0xF8, 0xA3, 0xE0, 0xF9,
+0xA3, 0xE0, 0x90, 0xFE, 0x6B, 0xF0, 0xA3, 0xE9,
+0xF0, 0xA3, 0xE8, 0xF0, 0x90, 0xFE, 0x68, 0x74,
+0x00, 0xF0, 0xC2, 0x08, 0x90, 0xFE, 0x6E, 0x74,
+0xB1, 0xF0, 0xC2, 0x09, 0x12, 0xE7, 0xB0, 0x20,
+0x08, 0x0E, 0x12, 0xE7, 0xBC, 0x30, 0x3E, 0xF7,
+0x90, 0xFE, 0xD8, 0x74, 0x01, 0xF0, 0xD2, 0x09,
+0x20, 0x09, 0x1E, 0x90, 0xFE, 0x70, 0xE0, 0x44,
+0x10, 0xF0, 0x54, 0xEF, 0xF0, 0x12, 0x2F, 0x59,
+0xEF, 0x60, 0x0E, 0x75, 0x3C, 0x00, 0x75, 0x3D,
+0x00, 0x75, 0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3,
+0x22, 0xC3, 0x22, 0x7B, 0x03, 0x7C, 0xE9, 0x7D,
+0xCD, 0x7E, 0xE9, 0x7F, 0xD7, 0x12, 0x2F, 0x71,
+0x12, 0xE3, 0xAA, 0x90, 0xE9, 0xD5, 0xE0, 0x60,
+0x12, 0xF9, 0x12, 0xE7, 0x17, 0x40, 0x01, 0x22,
+0x90, 0xF6, 0x00, 0x78, 0x06, 0x74, 0xFF, 0xF0,
+0xA3, 0xD8, 0xFC, 0x74, 0x01, 0x90, 0xE9, 0xCB,
+0xF0, 0xE5, 0x3E, 0xC3, 0x13, 0x90, 0xE9, 0xCA,
+0xF0, 0xC0, 0xE0, 0x75, 0xF0, 0x02, 0xC0, 0xF0,
+0x12, 0xE2, 0x2F, 0xEF, 0x70, 0x21, 0x20, 0x37,
+0x07, 0x20, 0x09, 0x04, 0xD0, 0xF0, 0x80, 0x05,
+0xD0, 0xF0, 0xD5, 0xF0, 0xE9, 0xD0, 0xE0, 0x90,
+0xFF, 0x28, 0xE0, 0x30, 0xE7, 0xFC, 0x90, 0xFF,
+0x28, 0xE0, 0x44, 0x01, 0xF0, 0xC3, 0x22, 0xD0,
+0xF0, 0x90, 0xE9, 0xD2, 0xE0, 0x24, 0x01, 0xF0,
+0x90, 0xE9, 0xD1, 0xE0, 0x34, 0x00, 0xF0, 0x90,
+0xE9, 0xD0, 0xE0, 0x34, 0x00, 0xF0, 0xD0, 0xE0,
+0x14, 0x70, 0xB6, 0x90, 0xE9, 0xD5, 0xE0, 0xF8,
+0x90, 0xE9, 0xCA, 0xE0, 0x28, 0xF5, 0xF0, 0xC3,
+0x74, 0x20, 0x95, 0xF0, 0x60, 0x22, 0xF9, 0x90,
+0xE9, 0xCA, 0xE0, 0xF5, 0xF0, 0x90, 0xE9, 0xCF,
+0xE0, 0x25, 0xF0, 0xF0, 0x90, 0xE9, 0xCE, 0xE0,
+0x34, 0x00, 0xF0, 0x90, 0xE9, 0xCD, 0xE0, 0x34,
+0x00, 0xF0, 0x12, 0xE7, 0x17, 0x40, 0x01, 0x22,
+0x90, 0xE9, 0xD6, 0xE0, 0x70, 0x13, 0x7B, 0x03,
+0x7C, 0xE9, 0x7D, 0xD7, 0x7E, 0xE9, 0x7F, 0xD0,
+0x12, 0x2F, 0x71, 0x12, 0xE5, 0xE0, 0x40, 0x01,
+0x22, 0x75, 0x3C, 0x00, 0x75, 0x3D, 0x00, 0x75,
+0x3E, 0x00, 0x75, 0x3F, 0x00, 0xD3, 0x22, 0x90,
+0xE9, 0xD6, 0xE0, 0x60, 0x18, 0x74, 0xFF, 0x90,
+0xF4, 0x00, 0x78, 0xFF, 0xF0, 0xA3, 0x18, 0xB8,
+0x00, 0xFA, 0x78, 0xFF, 0xF0, 0xA3, 0x18, 0xB8,
+0x00, 0xFA, 0xF0, 0xA3, 0xF0, 0xC0, 0x01, 0x12,
+0xE7, 0x70, 0x40, 0x04, 0xD0, 0x01, 0xC3, 0x22,
+0x90, 0xE9, 0xCF, 0xE0, 0x24, 0x01, 0xF0, 0x90,
+0xE9, 0xCE, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9,
+0xCD, 0xE0, 0x34, 0x00, 0xF0, 0x90, 0xE9, 0xD2,
+0xE0, 0x24, 0x01, 0xF0, 0x90, 0xE9, 0xD1, 0xE0,
+0x34, 0x00, 0xF0, 0x90, 0xE9, 0xD0, 0xE0, 0x34,
+0x00, 0xF0, 0xD0, 0x01, 0xD9, 0xC7, 0xD3, 0x22,
+0xC2, 0x06, 0x90, 0xE9, 0xD6, 0xE0, 0x70, 0x28,
+0x12, 0xE0, 0xD8, 0xEF, 0x60, 0x03, 0x02, 0xE7,
+0xA0, 0x90, 0xEB, 0xC2, 0xE0, 0x60, 0x17, 0x64,
+0x02, 0x60, 0x15, 0x90, 0xF6, 0x00, 0x78, 0x06,
+0x74, 0xFF, 0xF0, 0xA3, 0xD8, 0xFC, 0x74, 0xF0,
+0x90, 0xF6, 0x04, 0xF0, 0x80, 0x02, 0xC3, 0x22,
+0xE4, 0x90, 0xE9, 0xCB, 0xF0, 0x12, 0xE2, 0x2F,
+0xEF, 0x70, 0x03, 0x02, 0xE7, 0x81, 0xD3, 0x22,
+0xC2, 0x3E, 0x75, 0x7C, 0x00, 0x75, 0x7D, 0x00,
+0x75, 0x7E, 0x00, 0x22, 0x05, 0x7C, 0xE5, 0x7C,
+0x70, 0x14, 0x05, 0x7D, 0xE5, 0x7D, 0x70, 0x04,
+0x05, 0x7E, 0x80, 0x0A, 0xB4, 0x17, 0x07, 0xE5,
+0x7E, 0xB4, 0x06, 0x02, 0xD2, 0x3E, 0x22, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x58, 0x44, 0x2D, 0x52, 0x57, 0x20, 0x20, 0x20,
+0x20, 0x20, 0x20, 0x31, 0x30, 0x30, 0x30, 0x30 };
+
diff --git a/drivers/staging/keucr/scsiglue.c b/drivers/staging/keucr/scsiglue.c
new file mode 100644
index 00000000000..7d8d444910c
--- /dev/null
+++ b/drivers/staging/keucr/scsiglue.c
@@ -0,0 +1,467 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_devinfo.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+/* Host functions */
+/*
+ * host_info()
+ */
+static const char *host_info(struct Scsi_Host *host)
+{
+ /* pr_info("scsiglue --- host_info\n"); */
+ return "SCSI emulation for USB Mass Storage devices";
+}
+
+/*
+ * slave_alloc()
+ */
+static int slave_alloc(struct scsi_device *sdev)
+{
+ struct us_data *us = host_to_us(sdev->host);
+
+ /* pr_info("scsiglue --- slave_alloc\n"); */
+ sdev->inquiry_len = 36;
+
+ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
+
+ if (us->subclass == USB_SC_UFI)
+ sdev->sdev_target->pdt_1f_for_no_lun = 1;
+
+ return 0;
+}
+
+/*
+ * slave_configure()
+ */
+static int slave_configure(struct scsi_device *sdev)
+{
+ struct us_data *us = host_to_us(sdev->host);
+
+ /* pr_info("scsiglue --- slave_configure\n"); */
+ if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) {
+ unsigned int max_sectors = 64;
+
+ if (us->fflags & US_FL_MAX_SECTORS_MIN)
+ max_sectors = PAGE_CACHE_SIZE >> 9;
+ if (queue_max_sectors(sdev->request_queue) > max_sectors)
+ blk_queue_max_hw_sectors(sdev->request_queue,
+ max_sectors);
+ }
+
+ if (sdev->type == TYPE_DISK) {
+ if (us->subclass != USB_SC_SCSI &&
+ us->subclass != USB_SC_CYP_ATACB)
+ sdev->use_10_for_ms = 1;
+ sdev->use_192_bytes_for_3f = 1;
+ if (us->fflags & US_FL_NO_WP_DETECT)
+ sdev->skip_ms_page_3f = 1;
+ sdev->skip_ms_page_8 = 1;
+ if (us->fflags & US_FL_FIX_CAPACITY)
+ sdev->fix_capacity = 1;
+ if (us->fflags & US_FL_CAPACITY_HEURISTICS)
+ sdev->guess_capacity = 1;
+ if (sdev->scsi_level > SCSI_2)
+ sdev->sdev_target->scsi_level = sdev->scsi_level
+ = SCSI_2;
+ sdev->retry_hwerror = 1;
+ sdev->allow_restart = 1;
+ sdev->last_sector_bug = 1;
+ } else {
+ sdev->use_10_for_ms = 1;
+ }
+
+ if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_CBI) &&
+ sdev->scsi_level == SCSI_UNKNOWN)
+ us->max_lun = 0;
+
+ if (us->fflags & US_FL_NOT_LOCKABLE)
+ sdev->lockable = 0;
+
+ return 0;
+}
+
+/* This is always called with scsi_lock(host) held */
+/*
+ * queuecommand()
+ */
+static int queuecommand_lck(struct scsi_cmnd *srb,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct us_data *us = host_to_us(srb->device->host);
+
+ /* pr_info("scsiglue --- queuecommand\n"); */
+
+ /* check for state-transition errors */
+ if (us->srb != NULL) {
+ /* pr_info("Error in %s: us->srb = %p\n"
+ __func__, us->srb); */
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ /* fail the command if we are disconnecting */
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ pr_info("Fail command during disconnect\n");
+ srb->result = DID_NO_CONNECT << 16;
+ done(srb);
+ return 0;
+ }
+
+ /* enqueue the command and wake up the control thread */
+ srb->scsi_done = done;
+ us->srb = srb;
+ complete(&us->cmnd_ready);
+
+ return 0;
+}
+
+static DEF_SCSI_QCMD(queuecommand)
+
+/***********************************************************************
+ * Error handling functions
+ ***********************************************************************/
+
+/* Command timeout and abort */
+/*
+ * command_abort()
+ */
+static int command_abort(struct scsi_cmnd *srb)
+{
+ struct us_data *us = host_to_us(srb->device->host);
+
+ /* pr_info("scsiglue --- command_abort\n"); */
+
+ scsi_lock(us_to_host(us));
+ if (us->srb != srb) {
+ scsi_unlock(us_to_host(us));
+ dev_info(&us->pusb_dev->dev, "-- nothing to abort\n");
+ return FAILED;
+ }
+
+ set_bit(US_FLIDX_TIMED_OUT, &us->dflags);
+ if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) {
+ set_bit(US_FLIDX_ABORTING, &us->dflags);
+ usb_stor_stop_transport(us);
+ }
+ scsi_unlock(us_to_host(us));
+
+ /* Wait for the aborted command to finish */
+ wait_for_completion(&us->notify);
+ return SUCCESS;
+}
+
+/* This invokes the transport reset mechanism to reset the state of the
+ * device.
+ */
+/*
+ * device_reset()
+ */
+static int device_reset(struct scsi_cmnd *srb)
+{
+ struct us_data *us = host_to_us(srb->device->host);
+ int result;
+
+ /* pr_info("scsiglue --- device_reset\n"); */
+
+ /* lock the device pointers and do the reset */
+ mutex_lock(&(us->dev_mutex));
+ result = us->transport_reset(us);
+ mutex_unlock(&us->dev_mutex);
+
+ return result < 0 ? FAILED : SUCCESS;
+}
+
+/*
+ * bus_reset()
+ */
+static int bus_reset(struct scsi_cmnd *srb)
+{
+ struct us_data *us = host_to_us(srb->device->host);
+ int result;
+
+ /* pr_info("scsiglue --- bus_reset\n"); */
+ result = usb_stor_port_reset(us);
+ return result < 0 ? FAILED : SUCCESS;
+}
+
+/*
+ * usb_stor_report_device_reset()
+ */
+void usb_stor_report_device_reset(struct us_data *us)
+{
+ int i;
+ struct Scsi_Host *host = us_to_host(us);
+
+ /* pr_info("scsiglue --- usb_stor_report_device_reset\n"); */
+ scsi_report_device_reset(host, 0, 0);
+ if (us->fflags & US_FL_SCM_MULT_TARG) {
+ for (i = 1; i < host->max_id; ++i)
+ scsi_report_device_reset(host, 0, i);
+ }
+}
+
+/*
+ * usb_stor_report_bus_reset()
+ */
+void usb_stor_report_bus_reset(struct us_data *us)
+{
+ struct Scsi_Host *host = us_to_host(us);
+
+ /* pr_info("scsiglue --- usb_stor_report_bus_reset\n"); */
+ scsi_lock(host);
+ scsi_report_bus_reset(host, 0);
+ scsi_unlock(host);
+}
+
+/***********************************************************************
+ * /proc/scsi/ functions
+ ***********************************************************************/
+
+/* we use this macro to help us write into the buffer */
+#undef SPRINTF
+#define SPRINTF(args...) seq_printf(m, ##args)
+
+static int write_info(struct Scsi_Host *host, char *buffer, int length)
+{
+ return length;
+}
+
+static int show_info(struct seq_file *m, struct Scsi_Host *host)
+{
+ struct us_data *us = host_to_us(host);
+ const char *string;
+
+ /* print the controller name */
+ SPRINTF(" Host scsi%d: usb-storage\n", host->host_no);
+
+ /* print product, vendor, and serial number strings */
+ if (us->pusb_dev->manufacturer)
+ string = us->pusb_dev->manufacturer;
+ else if (us->unusual_dev->vendorName)
+ string = us->unusual_dev->vendorName;
+ else
+ string = "Unknown";
+ SPRINTF(" Vendor: %s\n", string);
+ if (us->pusb_dev->product)
+ string = us->pusb_dev->product;
+ else if (us->unusual_dev->productName)
+ string = us->unusual_dev->productName;
+ else
+ string = "Unknown";
+ SPRINTF(" Product: %s\n", string);
+ if (us->pusb_dev->serial)
+ string = us->pusb_dev->serial;
+ else
+ string = "None";
+ SPRINTF("Serial Number: %s\n", string);
+
+ /* show the protocol and transport */
+ SPRINTF(" Protocol: %s\n", us->protocol_name);
+ SPRINTF(" Transport: %s\n", us->transport_name);
+
+ /* show the device flags */
+ SPRINTF(" Quirks:");
+
+#define US_FLAG(name, value) \
+ do { \
+ if (us->fflags & value) \
+ SPRINTF(" " #name); \
+ } while (0);
+US_DO_ALL_FLAGS
+#undef US_FLAG
+ seq_putc(m, '\n');
+ return 0;
+}
+
+/***********************************************************************
+ * Sysfs interface
+ ***********************************************************************/
+
+/* Output routine for the sysfs max_sectors file */
+static ssize_t max_sectors_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ /* pr_info("scsiglue --- ssize_t show_max_sectors\n"); */
+ return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue));
+}
+
+/* Input routine for the sysfs max_sectors file */
+static ssize_t max_sectors_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned short ms;
+
+ /* pr_info("scsiglue --- ssize_t store_max_sectors\n"); */
+ if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
+ blk_queue_max_hw_sectors(sdev->request_queue, ms);
+ return strlen(buf);
+ }
+ return -EINVAL;
+}
+static DEVICE_ATTR_RW(max_sectors);
+
+static struct device_attribute *sysfs_device_attr_list[] = {
+ &dev_attr_max_sectors, NULL,
+};
+
+/* this defines our host template, with which we'll allocate hosts */
+
+/*
+ * usb_stor_host_template()
+ */
+struct scsi_host_template usb_stor_host_template = {
+ /* basic userland interface stuff */
+ .name = "eucr-storage",
+ .proc_name = "eucr-storage",
+ .write_info = write_info,
+ .show_info = show_info,
+ .info = host_info,
+
+ /* command interface -- queued only */
+ .queuecommand = queuecommand,
+
+ /* error and abort handlers */
+ .eh_abort_handler = command_abort,
+ .eh_device_reset_handler = device_reset,
+ .eh_bus_reset_handler = bus_reset,
+
+ /* queue commands only, only one command per LUN */
+ .can_queue = 1,
+ .cmd_per_lun = 1,
+
+ /* unknown initiator id */
+ .this_id = -1,
+
+ .slave_alloc = slave_alloc,
+ .slave_configure = slave_configure,
+
+ /* lots of sg segments can be handled */
+ .sg_tablesize = SG_ALL,
+
+ /* limit the total size of a transfer to 120 KB */
+ .max_sectors = 240,
+
+ /* merge commands... this seems to help performance, but
+ * periodically someone should test to see which setting is more
+ * optimal.
+ */
+ .use_clustering = 1,
+
+ /* emulated HBA */
+ .emulated = 1,
+
+ /* we do our own delay after a device or bus reset */
+ .skip_settle_delay = 1,
+
+ /* sysfs device attributes */
+ .sdev_attrs = sysfs_device_attr_list,
+
+ /* module management */
+ .module = THIS_MODULE
+};
+
+/* To Report "Illegal Request: Invalid Field in CDB */
+unsigned char usb_stor_sense_invalidCDB[18] = {
+ [0] = 0x70, /* current error */
+ [2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */
+ [7] = 0x0a, /* additional length */
+ [12] = 0x24 /* Invalid Field in CDB */
+};
+
+/***********************************************************************
+ * Scatter-gather transfer buffer access routines
+ ***********************************************************************/
+
+/*
+ * usb_stor_access_xfer_buf()
+ */
+unsigned int usb_stor_access_xfer_buf(struct us_data *us,
+ unsigned char *buffer, unsigned int buflen,
+ struct scsi_cmnd *srb, struct scatterlist **sgptr,
+ unsigned int *offset, enum xfer_buf_dir dir)
+{
+ unsigned int cnt;
+
+ /* pr_info("transport --- usb_stor_access_xfer_buf\n"); */
+ struct scatterlist *sg = *sgptr;
+
+ if (!sg)
+ sg = scsi_sglist(srb);
+
+ cnt = 0;
+ while (cnt < buflen && sg) {
+ struct page *page = sg_page(sg) +
+ ((sg->offset + *offset) >> PAGE_SHIFT);
+ unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
+ unsigned int sglen = sg->length - *offset;
+
+ if (sglen > buflen - cnt) {
+ /* Transfer ends within this s-g entry */
+ sglen = buflen - cnt;
+ *offset += sglen;
+ } else {
+ /* Transfer continues to next s-g entry */
+ *offset = 0;
+ sg = sg_next(sg);
+ }
+
+ while (sglen > 0) {
+ unsigned int plen = min(sglen,
+ (unsigned int)PAGE_SIZE - poff);
+ unsigned char *ptr = kmap(page);
+
+ if (dir == TO_XFER_BUF)
+ memcpy(ptr + poff, buffer + cnt, plen);
+ else
+ memcpy(buffer + cnt, ptr + poff, plen);
+ kunmap(page);
+
+ /* Start at the beginning of the next page */
+ poff = 0;
+ ++page;
+ cnt += plen;
+ sglen -= plen;
+ }
+ }
+ *sgptr = sg;
+
+ /* Return the amount actually transferred */
+ return cnt;
+}
+
+/*
+ * Store the contents of buffer into srb's transfer
+ * buffer and set the SCSI residue.
+ */
+/*
+ * usb_stor_set_xfer_buf()
+ */
+void usb_stor_set_xfer_buf(struct us_data *us, unsigned char *buffer,
+ unsigned int buflen, struct scsi_cmnd *srb, unsigned int dir)
+{
+ unsigned int offset = 0;
+ struct scatterlist *sg = NULL;
+
+ /* pr_info("transport --- usb_stor_set_xfer_buf\n"); */
+ /* TO_XFER_BUF = 0, FROM_XFER_BUF = 1 */
+ buflen = min(buflen, scsi_bufflen(srb));
+ buflen = usb_stor_access_xfer_buf(us, buffer, buflen, srb,
+ &sg, &offset, dir);
+ if (buflen < scsi_bufflen(srb))
+ scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
+}
diff --git a/drivers/staging/keucr/scsiglue.h b/drivers/staging/keucr/scsiglue.h
new file mode 100644
index 00000000000..c7e59f0f9cd
--- /dev/null
+++ b/drivers/staging/keucr/scsiglue.h
@@ -0,0 +1,10 @@
+#ifndef _SCSIGLUE_H_
+#define _SCSIGLUE_H_
+
+extern void usb_stor_report_device_reset(struct us_data *us);
+extern void usb_stor_report_bus_reset(struct us_data *us);
+
+extern unsigned char usb_stor_sense_invalidCDB[18];
+extern struct scsi_host_template usb_stor_host_template;
+
+#endif
diff --git a/drivers/staging/keucr/smcommon.h b/drivers/staging/keucr/smcommon.h
new file mode 100644
index 00000000000..1d2752a1d5c
--- /dev/null
+++ b/drivers/staging/keucr/smcommon.h
@@ -0,0 +1,29 @@
+/*----- < SMCommon.h> --------------------------------------------------*/
+#ifndef SMCOMMON_INCD
+#define SMCOMMON_INCD
+
+
+/***************************************************************************
+Define Definition
+***************************************************************************/
+#define SMSUCCESS 0x0000 /* SUCCESS */
+#define ERROR 0xFFFF /* ERROR */
+#define CORRECT 0x0001 /* CORRECTABLE */
+
+/***************************************************************************/
+#define NO_ERROR 0x0000 /* NO ERROR */
+#define ERR_WriteFault 0x0003 /* Peripheral Device Write Fault */
+#define ERR_HwError 0x0004 /* Hardware Error */
+#define ERR_DataStatus 0x0010 /* DataStatus Error */
+#define ERR_EccReadErr 0x0011 /* Unrecovered Read Error */
+#define ERR_CorReadErr 0x0018 /* Recovered Read Data with ECC */
+#define ERR_OutOfLBA 0x0021 /* Illegal Logical Block Address */
+#define ERR_WrtProtect 0x0027 /* Write Protected */
+#define ERR_ChangedMedia 0x0028 /* Medium Changed */
+#define ERR_UnknownMedia 0x0030 /* Incompatible Medium Installed */
+#define ERR_IllegalFmt 0x0031 /* Medium Format Corrupted */
+#define ERR_NoSmartMedia 0x003A /* Medium Not Present */
+
+/***************************************************************************/
+
+#endif
diff --git a/drivers/staging/keucr/smil.h b/drivers/staging/keucr/smil.h
new file mode 100644
index 00000000000..f938759337e
--- /dev/null
+++ b/drivers/staging/keucr/smil.h
@@ -0,0 +1,288 @@
+/*----- < smil.h> ----------------------------------------------------*/
+#ifndef SMIL_INCD
+#define SMIL_INCD
+
+/***************************************************************************
+Define Definition
+***************************************************************************/
+#define K_BYTE 1024 /* Kilo Byte */
+#define SECTSIZE 512 /* Sector buffer size */
+#define REDTSIZE 16 /* Redundant buffer size */
+
+/***************************************************************************/
+#define DUMMY_DATA 0xFF /* No Assign Sector Read Data */
+
+/***************************************************************************
+Max Zone/Block/Sectors Data Definition
+***************************************************************************/
+#define MAX_ZONENUM 128 /* Max Zone Numbers in a SmartMedia */
+#define MAX_BLOCKNUM 0x0400 /* Max Block Numbers in a Zone */
+#define MAX_SECTNUM 0x20 /* Max Sector Numbers in a Block */
+#define MAX_LOGBLOCK 1000 /* Max Logical Block Numbers in a Zone */
+
+/***************************************************************************/
+#define CIS_SEARCH_SECT 0x08 /* Max CIS Search Sector Number */
+
+/***************************************************************************
+Logical to Physical Block Table Data Definition
+***************************************************************************/
+#define NO_ASSIGN 0xFFFF /* No Assign Logical Block Address */
+
+/***************************************************************************
+'SectCopyMode' Data
+***************************************************************************/
+#define COMPLETED 0 /* Sector Copy Completed */
+#define REQ_ERASE 1 /* Request Read Block Erase */
+#define REQ_FAIL 2 /* Request Read Block Failed */
+
+/***************************************************************************
+Retry Counter Definition
+***************************************************************************/
+#define RDERR_REASSIGN 1 /* Reassign with Read Error */
+#define L2P_ERR_ERASE 1 /* BlockErase for Contradicted L2P Table */
+
+/***************************************************************************
+Hardware ECC Definition
+***************************************************************************/
+#define HW_ECC_SUPPORTED 1 /* Hardware ECC Supported */
+/* No definition for Software ECC */
+
+/***************************************************************************
+SmartMedia Command & Status Definition
+***************************************************************************/
+/* SmartMedia Command */
+#define WRDATA 0x80
+/* #define READ 0x00 */
+#define READ_REDT 0x50
+/* #define WRITE 0x10 */
+#define RDSTATUS 0x70
+
+#define READ1 0x00 /* NO */
+#define READ2 0x01 /* NO */
+#define READ3 0x50 /* NO */
+#define RST_CHIP 0xFF
+#define ERASE1 0x60
+#define ERASE2 0xD0
+#define READ_ID_1 0x90
+#define READ_ID_2 0x91
+#define READ_ID_3 0x9A
+
+/* 712 SmartMedia Command */
+#define SM_CMD_RESET 0x00 /* 0xFF */
+#define SM_CMD_READ_ID_1 0x10 /* 0x90 */
+#define SM_CMD_READ_ID_2 0x20 /* 0x91 */
+#define SM_CMD_READ_STAT 0x30 /* 0x70 */
+#define SM_CMD_RDMULTPL_STAT 0x40 /* 0x71 */
+#define SM_CMD_READ_1 0x50 /* 0x00 */
+#define SM_CMD_READ_2 0x60 /* 0x01 */
+#define SM_CMD_READ_3 0x70 /* 0x50 */
+#define SM_CMD_PAGPRGM_TRUE 0x80 /* {0x80, 0x10} */
+#define SM_CMD_PAGPRGM_DUMY 0x90 /* {0x80, 0x11} */
+#define SM_CMD_PAGPRGM_MBLK 0xA0 /* {0x80, 0x15} */
+#define SM_CMD_BLKERASE 0xB0 /* {0x60, 0xD0} */
+#define SM_CMD_BLKERASE_MULTPL 0xC0 /* {0x60-0x60, 0xD0} */
+
+#define SM_CRADDTCT_DEBNCETIMER_EN 0x02
+#define SM_CMD_START_BIT 0x01
+
+#define SM_WaitCmdDone { while (!SM_CmdDone); }
+#define SM_WaitDmaDone { while (!SM_DmaDone); }
+
+/* SmartMedia Status */
+#define WR_FAIL 0x01 /* 0:Pass, 1:Fail */
+#define SUSPENDED 0x20 /* 0:Not Suspended, 1:Suspended */
+#define READY 0x40 /* 0:Busy, 1:Ready */
+#define WR_PRTCT 0x80 /* 0:Protect, 1:Not Protect */
+
+/* SmartMedia Busy Time (1bit:0.1ms) */
+#define BUSY_PROG 200 /* tPROG : 20ms ----- Program Time old : 200 */
+#define BUSY_ERASE 4000 /* tBERASE : 400ms ----- Block Erase Time old : 4000 */
+
+/*for 712 Test */
+/* #define BUSY_READ 1 *//* tR : 100us ----- Data transfer Time old : 1 */
+/* #define BUSY_READ 10 *//* tR : 100us ----- Data transfer Time old : 1 */
+
+#define BUSY_READ 200 /* tR : 20ms ----- Data transfer Time old : 1 */
+
+/* #define BUSY_RESET 60 *//* tRST : 6ms ----- Device Resetting Time old : 60 */
+
+#define BUSY_RESET 600 /* tRST : 60ms ----- Device Resetting Time old : 60 */
+
+/* Hardware Timer (1bit:0.1ms) */
+#define TIME_PON 3000 /* 300ms ------ Power On Wait Time */
+#define TIME_CDCHK 200 /* 20ms ------ Card Check Interval Timer */
+#define TIME_WPCHK 50 /* 5ms ------ WP Check Interval Timer */
+#define TIME_5VCHK 10 /* 1ms ------ 5V Check Interval Timer */
+
+/***************************************************************************
+Redundant Data
+***************************************************************************/
+#define REDT_DATA 0x04
+#define REDT_BLOCK 0x05
+#define REDT_ADDR1H 0x06
+#define REDT_ADDR1L 0x07
+#define REDT_ADDR2H 0x0B
+#define REDT_ADDR2L 0x0C
+#define REDT_ECC10 0x0D
+#define REDT_ECC11 0x0E
+#define REDT_ECC12 0x0F
+#define REDT_ECC20 0x08
+#define REDT_ECC21 0x09
+#define REDT_ECC22 0x0A
+
+/***************************************************************************
+SmartMedia Model & Attribute
+***************************************************************************/
+/* SmartMedia Attribute */
+#define NOWP 0x00 /* 0... .... No Write Protect */
+#define WP 0x80 /* 1... .... Write Protected */
+#define MASK 0x00 /* .00. .... NAND MASK ROM Model */
+#define FLASH 0x20 /* .01. .... NAND Flash ROM Model */
+#define AD3CYC 0x00 /* ...0 .... Address 3-cycle */
+#define AD4CYC 0x10 /* ...1 .... Address 4-cycle */
+#define BS16 0x00 /* .... 00.. 16page/block */
+#define BS32 0x04 /* .... 01.. 32page/block */
+#define PS256 0x00 /* .... ..00 256byte/page */
+#define PS512 0x01 /* .... ..01 512byte/page */
+#define MWP 0x80 /* WriteProtect mask */
+#define MFLASH 0x60 /* Flash Rom mask */
+#define MADC 0x10 /* Address Cycle */
+#define MBS 0x0C /* BlockSize mask */
+#define MPS 0x03 /* PageSize mask */
+
+/* SmartMedia Model */
+#define NOSSFDC 0x00 /* NO SmartMedia */
+#define SSFDC1MB 0x01 /* 1MB SmartMedia */
+#define SSFDC2MB 0x02 /* 2MB SmartMedia */
+#define SSFDC4MB 0x03 /* 4MB SmartMedia */
+#define SSFDC8MB 0x04 /* 8MB SmartMedia */
+#define SSFDC16MB 0x05 /* 16MB SmartMedia */
+#define SSFDC32MB 0x06 /* 32MB SmartMedia */
+#define SSFDC64MB 0x07 /* 64MB SmartMedia */
+#define SSFDC128MB 0x08 /*128MB SmartMedia */
+#define SSFDC256MB 0x09
+#define SSFDC512MB 0x0A
+#define SSFDC1GB 0x0B
+#define SSFDC2GB 0x0C
+
+/***************************************************************************
+Struct Definition
+***************************************************************************/
+struct keucr_media_info {
+ u8 Model;
+ u8 Attribute;
+ u8 MaxZones;
+ u8 MaxSectors;
+ u16 MaxBlocks;
+ u16 MaxLogBlocks;
+};
+
+struct keucr_media_address {
+ u8 Zone; /* Zone Number */
+ u8 Sector; /* Sector(512byte) Number on Block */
+ u16 PhyBlock; /* Physical Block Number on Zone */
+ u16 LogBlock; /* Logical Block Number of Zone */
+};
+
+struct keucr_media_area {
+ u8 Sector; /* Sector(512byte) Number on Block */
+ u16 PhyBlock; /* Physical Block Number on Zone 0 */
+};
+
+extern u16 ReadBlock;
+extern u16 WriteBlock;
+extern u32 MediaChange;
+
+extern struct keucr_media_info Ssfdc;
+extern struct keucr_media_address Media;
+extern struct keucr_media_area CisArea;
+
+/*
+ * SMILMain.c
+ */
+/******************************************/
+int Init_D_SmartMedia(void);
+int Pwoff_D_SmartMedia(void);
+int Check_D_SmartMedia(void);
+int Check_D_MediaFmt(struct us_data *);
+int Check_D_Parameter(struct us_data *, u16 *, u8 *, u8 *);
+int Media_D_ReadSector(struct us_data *, u32, u16, u8 *);
+int Media_D_WriteSector(struct us_data *, u32, u16, u8 *);
+int Media_D_CopySector(struct us_data *, u32, u16, u8 *);
+int Media_D_EraseBlock(struct us_data *, u32, u16);
+int Media_D_EraseAll(struct us_data *);
+/******************************************/
+int Media_D_OneSectWriteStart(struct us_data *, u32, u8 *);
+int Media_D_OneSectWriteNext(struct us_data *, u8 *);
+int Media_D_OneSectWriteFlush(struct us_data *);
+
+/******************************************/
+extern int SM_FreeMem(void); /* ENE SM function */
+void SM_EnableLED(struct us_data *, bool);
+void Led_D_TernOn(void);
+void Led_D_TernOff(void);
+
+int Media_D_EraseAllRedtData(u32 Index, bool CheckBlock);
+/*DWORD Media_D_GetMediaInfo(struct us_data * fdoExt,
+ PIOCTL_MEDIA_INFO_IN pParamIn, PIOCTL_MEDIA_INFO_OUT pParamOut); */
+
+/*
+ * SMILSub.c
+ */
+/******************************************/
+int Check_D_DataBlank(u8 *);
+int Check_D_FailBlock(u8 *);
+int Check_D_DataStatus(u8 *);
+int Load_D_LogBlockAddr(u8 *);
+void Clr_D_RedundantData(u8 *);
+void Set_D_LogBlockAddr(u8 *);
+void Set_D_FailBlock(u8 *);
+void Set_D_DataStaus(u8 *);
+
+/******************************************/
+void Ssfdc_D_Reset(struct us_data *);
+int Ssfdc_D_ReadCisSect(struct us_data *, u8 *, u8 *);
+void Ssfdc_D_WriteRedtMode(void);
+void Ssfdc_D_ReadID(u8 *, u8);
+int Ssfdc_D_ReadSect(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_ReadBlock(struct us_data *, u16, u8 *, u8 *);
+int Ssfdc_D_WriteSect(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_WriteBlock(struct us_data *, u16, u8 *, u8 *);
+int Ssfdc_D_CopyBlock(struct us_data *, u16, u8 *, u8 *);
+int Ssfdc_D_WriteSectForCopy(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_EraseBlock(struct us_data *);
+int Ssfdc_D_ReadRedtData(struct us_data *, u8 *);
+int Ssfdc_D_WriteRedtData(struct us_data *, u8 *);
+int Ssfdc_D_CheckStatus(void);
+int Set_D_SsfdcModel(u8);
+void Cnt_D_Reset(void);
+int Cnt_D_PowerOn(void);
+void Cnt_D_PowerOff(void);
+void Cnt_D_LedOn(void);
+void Cnt_D_LedOff(void);
+int Check_D_CntPower(void);
+int Check_D_CardExist(void);
+int Check_D_CardStsChg(void);
+int Check_D_SsfdcWP(void);
+int SM_ReadBlock(struct us_data *, u8 *, u8 *);
+
+int Ssfdc_D_ReadSect_DMA(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_ReadSect_PIO(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_WriteSect_DMA(struct us_data *, u8 *, u8 *);
+int Ssfdc_D_WriteSect_PIO(struct us_data *, u8 *, u8 *);
+
+/******************************************/
+int Check_D_ReadError(u8 *);
+int Check_D_Correct(u8 *, u8 *);
+int Check_D_CISdata(u8 *, u8 *);
+void Set_D_RightECC(u8 *);
+
+/*
+ * SMILECC.c
+ */
+void calculate_ecc(u8 *, u8 *, u8 *, u8 *, u8 *);
+u8 correct_data(u8 *, u8 *, u8, u8, u8);
+int _Correct_D_SwECC(u8 *, u8 *, u8 *);
+void _Calculate_D_SwECC(u8 *, u8 *);
+
+#endif /* already included */
diff --git a/drivers/staging/keucr/smilecc.c b/drivers/staging/keucr/smilecc.c
new file mode 100644
index 00000000000..ffe6030f5e4
--- /dev/null
+++ b/drivers/staging/keucr/smilecc.c
@@ -0,0 +1,211 @@
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+/* #include "stdlib.h" */
+/* #include "EUCR6SK.h" */
+#include "smcommon.h"
+#include "smil.h"
+
+/* #include <stdio.h> */
+/* #include <stdlib.h> */
+/* #include <string.h> */
+/* #include <dos.h> */
+/* #include "EMCRIOS.h" */
+
+/* CP0-CP5 code table */
+static u8 ecctable[256] = {
+0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F, 0x5A, 0x5A, 0x0F, 0x0C, 0x59, 0x03,
+0x56, 0x55, 0x00, 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, 0x3F, 0x6A,
+0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, 0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69,
+0x3C, 0x3C, 0x69, 0x6A, 0x3F, 0x65, 0x30, 0x33, 0x66, 0x03, 0x56, 0x55, 0x00,
+0x5A, 0x0F, 0x0C, 0x59, 0x59, 0x0C, 0x0F, 0x5A, 0x00, 0x55, 0x56, 0x03, 0x69,
+0x3C, 0x3F, 0x6A, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6A, 0x3F,
+0x3C, 0x69, 0x0C, 0x59, 0x5A, 0x0F, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00,
+0x55, 0x0F, 0x5A, 0x59, 0x0C, 0x0F, 0x5A, 0x59, 0x0C, 0x56, 0x03, 0x00, 0x55,
+0x55, 0x00, 0x03, 0x56, 0x0C, 0x59, 0x5A, 0x0F, 0x6A, 0x3F, 0x3C, 0x69, 0x33,
+0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3C, 0x3F, 0x6A, 0x6A, 0x3F,
+0x3C, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3C, 0x3F,
+0x6A, 0x0F, 0x5A, 0x59, 0x0C, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56,
+0x0C, 0x59, 0x5A, 0x0F, 0x0C, 0x59, 0x5A, 0x0F, 0x55, 0x00, 0x03, 0x56, 0x56,
+0x03, 0x00, 0x55, 0x0F, 0x5A, 0x59, 0x0C, 0x69, 0x3C, 0x3F, 0x6A, 0x30, 0x65,
+0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6A, 0x3F, 0x3C, 0x69, 0x03, 0x56, 0x55,
+0x00, 0x5A, 0x0F, 0x0C, 0x59, 0x59, 0x0C, 0x0F, 0x5A, 0x00, 0x55, 0x56, 0x03,
+0x66, 0x33, 0x30, 0x65, 0x3F, 0x6A, 0x69, 0x3C, 0x3C, 0x69, 0x6A, 0x3F, 0x65,
+0x30, 0x33, 0x66, 0x65, 0x30, 0x33, 0x66, 0x3C, 0x69, 0x6A, 0x3F, 0x3F, 0x6A,
+0x69, 0x3C, 0x66, 0x33, 0x30, 0x65, 0x00, 0x55, 0x56, 0x03, 0x59, 0x0C, 0x0F,
+0x5A, 0x5A, 0x0F, 0x0C, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+static void trans_result(u8, u8, u8 *, u8 *);
+
+#define BIT7 0x80
+#define BIT6 0x40
+#define BIT5 0x20
+#define BIT4 0x10
+#define BIT3 0x08
+#define BIT2 0x04
+#define BIT1 0x02
+#define BIT0 0x01
+#define BIT1BIT0 0x03
+#define BIT23 0x00800000L
+#define MASK_CPS 0x3f
+#define CORRECTABLE 0x00555554L
+
+/*
+ * reg2; * LP14,LP12,LP10,...
+ * reg3; * LP15,LP13,LP11,...
+ * *ecc1; * LP15,LP14,LP13,...
+ * *ecc2; * LP07,LP06,LP05,...
+ */
+static void trans_result(u8 reg2, u8 reg3, u8 *ecc1, u8 *ecc2)
+{
+ u8 a; /* Working for reg2,reg3 */
+ u8 b; /* Working for ecc1,ecc2 */
+ u8 i; /* For counting */
+
+ a = BIT7; b = BIT7; /* 80h=10000000b */
+ *ecc1 = *ecc2 = 0; /* Clear ecc1,ecc2 */
+ for (i = 0; i < 4; ++i) {
+ if ((reg3&a) != 0)
+ *ecc1 |= b; /* LP15,13,11,9 -> ecc1 */
+ b = b>>1; /* Right shift */
+ if ((reg2&a) != 0)
+ *ecc1 |= b; /* LP14,12,10,8 -> ecc1 */
+ b = b>>1; /* Right shift */
+ a = a>>1; /* Right shift */
+ }
+
+ b = BIT7; /* 80h=10000000b */
+ for (i = 0; i < 4; ++i) {
+ if ((reg3&a) != 0)
+ *ecc2 |= b; /* LP7,5,3,1 -> ecc2 */
+ b = b>>1; /* Right shift */
+ if ((reg2&a) != 0)
+ *ecc2 |= b; /* LP6,4,2,0 -> ecc2 */
+ b = b>>1; /* Right shift */
+ a = a>>1; /* Right shift */
+ }
+}
+
+/*static void calculate_ecc(table,data,ecc1,ecc2,ecc3) */
+/*
+ * *table; * CP0-CP5 code table
+ * *data; * DATA
+ * *ecc1; * LP15,LP14,LP13,...
+ * *ecc2; * LP07,LP06,LP05,...
+ * *ecc3; * CP5,CP4,CP3,...,"1","1"
+ */
+void calculate_ecc(u8 *table, u8 *data, u8 *ecc1, u8 *ecc2, u8 *ecc3)
+{
+ u32 i; /* For counting */
+ u8 a; /* Working for table */
+ u8 reg1; /* D-all,CP5,CP4,CP3,... */
+ u8 reg2; /* LP14,LP12,L10,... */
+ u8 reg3; /* LP15,LP13,L11,... */
+
+ reg1 = reg2 = reg3 = 0; /* Clear parameter */
+ for (i = 0; i < 256; ++i) {
+ a = table[data[i]]; /* Get CP0-CP5 code from table */
+ reg1 ^= (a&MASK_CPS); /* XOR with a */
+ if ((a&BIT6) != 0) { /* If D_all(all bit XOR) = 1 */
+ reg3 ^= (u8)i; /* XOR with counter */
+ reg2 ^= ~((u8)i); /* XOR with inv. of counter */
+ }
+ }
+
+ /* Trans LP14,12,10,... & LP15,13,11,... ->
+ LP15,14,13,... & LP7,6,5,.. */
+ trans_result(reg2, reg3, ecc1, ecc2);
+ *ecc1 = ~(*ecc1); *ecc2 = ~(*ecc2); /* Inv. ecc2 & ecc3 */
+ *ecc3 = ((~reg1)<<2)|BIT1BIT0; /* Make TEL format */
+}
+
+/*
+ * *data; * DATA
+ * *eccdata; * ECC DATA
+ * ecc1; * LP15,LP14,LP13,...
+ * ecc2; * LP07,LP06,LP05,...
+ * ecc3; * CP5,CP4,CP3,...,"1","1"
+ */
+u8 correct_data(u8 *data, u8 *eccdata, u8 ecc1, u8 ecc2, u8 ecc3)
+{
+ u32 l; /* Working to check d */
+ u32 d; /* Result of comparison */
+ u32 i; /* For counting */
+ u8 d1, d2, d3; /* Result of comparison */
+ u8 a; /* Working for add */
+ u8 add; /* Byte address of cor. DATA */
+ u8 b; /* Working for bit */
+ u8 bit; /* Bit address of cor. DATA */
+
+ d1 = ecc1^eccdata[1]; d2 = ecc2^eccdata[0]; /* Compare LP's */
+ d3 = ecc3^eccdata[2]; /* Compare CP's */
+ d = ((u32)d1<<16) /* Result of comparison */
+ +((u32)d2<<8)
+ +(u32)d3;
+
+ if (d == 0)
+ return 0; /* If No error, return */
+
+ if (((d^(d>>1))&CORRECTABLE) == CORRECTABLE) { /* If correctable */
+ l = BIT23;
+ add = 0; /* Clear parameter */
+ a = BIT7;
+
+ for (i = 0; i < 8; ++i) { /* Checking 8 bit */
+ if ((d&l) != 0)
+ add |= a; /* Make byte address from LP's */
+ l >>= 2; a >>= 1; /* Right Shift */
+ }
+
+ bit = 0; /* Clear parameter */
+ b = BIT2;
+ for (i = 0; i < 3; ++i) { /* Checking 3 bit */
+ if ((d&l) != 0)
+ bit |= b; /* Make bit address from CP's */
+ l >>= 2; b >>= 1; /* Right shift */
+ }
+
+ b = BIT0;
+ data[add] ^= (b<<bit); /* Put corrected data */
+ return 1;
+ }
+
+ i = 0; /* Clear count */
+ d &= 0x00ffffffL; /* Masking */
+
+ while (d) { /* If d=0 finish counting */
+ if (d&BIT0)
+ ++i; /* Count number of 1 bit */
+ d >>= 1; /* Right shift */
+ }
+
+ if (i == 1) { /* If ECC error */
+ eccdata[1] = ecc1; eccdata[0] = ecc2; /* Put right ECC code */
+ eccdata[2] = ecc3;
+ return 2;
+ }
+ return 3; /* Uncorrectable error */
+}
+
+int _Correct_D_SwECC(u8 *buf, u8 *redundant_ecc, u8 *calculate_ecc)
+{
+ u32 err;
+
+ err = correct_data(buf, redundant_ecc, *(calculate_ecc + 1),
+ *(calculate_ecc), *(calculate_ecc + 2));
+ if (err == 1)
+ memcpy(calculate_ecc, redundant_ecc, 3);
+
+ if (err == 0 || err == 1 || err == 2)
+ return 0;
+
+ return -1;
+}
+
+void _Calculate_D_SwECC(u8 *buf, u8 *ecc)
+{
+ calculate_ecc(ecctable, buf, ecc+1, ecc+0, ecc+2);
+}
+
+
diff --git a/drivers/staging/keucr/smilmain.c b/drivers/staging/keucr/smilmain.c
new file mode 100644
index 00000000000..42ec8a669ad
--- /dev/null
+++ b/drivers/staging/keucr/smilmain.c
@@ -0,0 +1,760 @@
+#include <linux/slab.h>
+#include "usb.h"
+#include "scsiglue.h"
+#include "smcommon.h"
+#include "smil.h"
+
+static int Conv_D_MediaAddr(struct us_data *, u32);
+static int Inc_D_MediaAddr(struct us_data *);
+static int Media_D_ReadOneSect(struct us_data *, u16, u8 *);
+
+static int Copy_D_BlockAll(struct us_data *, u32);
+
+static int Assign_D_WriteBlock(void);
+static int Release_D_ReadBlock(struct us_data *);
+static int Release_D_WriteBlock(struct us_data *);
+static int Release_D_CopySector(struct us_data *);
+
+static int Copy_D_PhyOneSect(struct us_data *);
+static int Read_D_PhyOneSect(struct us_data *, u16, u8 *);
+static int Erase_D_PhyOneBlock(struct us_data *);
+
+static int Set_D_PhyFmtValue(struct us_data *);
+static int Search_D_CIS(struct us_data *);
+static int Make_D_LogTable(struct us_data *);
+
+static int MarkFail_D_PhyOneBlock(struct us_data *);
+
+static u32 ErrCode;
+static u8 WorkBuf[SECTSIZE];
+static u8 Redundant[REDTSIZE];
+static u8 WorkRedund[REDTSIZE];
+/* 128 x 1000, Log2Phy[MAX_ZONENUM][MAX_LOGBLOCK]; */
+static u16 *Log2Phy[MAX_ZONENUM];
+static u8 Assign[MAX_ZONENUM][MAX_BLOCKNUM / 8];
+static u16 AssignStart[MAX_ZONENUM];
+u16 ReadBlock;
+u16 WriteBlock;
+u32 MediaChange;
+static u32 SectCopyMode;
+
+/* BIT Control Macro */
+static u8 BitData[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
+#define Set_D_Bit(a, b) (a[(u8)((b) / 8)] |= BitData[(b) % 8])
+#define Clr_D_Bit(a, b) (a[(u8)((b) / 8)] &= ~BitData[(b) % 8])
+#define Chk_D_Bit(a, b) (a[(u8)((b) / 8)] & BitData[(b) % 8])
+
+/* ----- SM_FreeMem() ------------------------------------------------- */
+int SM_FreeMem(void)
+{
+ int i;
+
+ pr_info("SM_FreeMem start\n");
+ for (i = 0; i < MAX_ZONENUM; i++) {
+ if (Log2Phy[i] != NULL) {
+ pr_info("Free Zone = %x, Addr = %p\n", i, Log2Phy[i]);
+ kfree(Log2Phy[i]);
+ Log2Phy[i] = NULL;
+ }
+ }
+ return NO_ERROR;
+}
+
+/* SmartMedia Read/Write/Erase Function */
+/* ----- Media_D_ReadSector() ------------------------------------------- */
+int Media_D_ReadSector(struct us_data *us, u32 start, u16 count, u8 *buf)
+{
+ u16 len, bn;
+
+ if (Conv_D_MediaAddr(us, start))
+ return ErrCode;
+
+ while (1) {
+ len = Ssfdc.MaxSectors - Media.Sector;
+ if (count > len)
+ bn = len;
+ else
+ bn = count;
+
+ if (Media_D_ReadOneSect(us, bn, buf)) {
+ ErrCode = ERR_EccReadErr;
+ return ErrCode;
+ }
+
+ Media.Sector += bn;
+ count -= bn;
+
+ if (count <= 0)
+ break;
+
+ buf += bn * SECTSIZE;
+
+ if (Inc_D_MediaAddr(us))
+ return ErrCode;
+ }
+
+ return NO_ERROR;
+}
+/* here */
+/* ----- Media_D_CopySector() ------------------------------------------ */
+int Media_D_CopySector(struct us_data *us, u32 start, u16 count, u8 *buf)
+{
+ u16 len, bn;
+
+ /* pr_info("Media_D_CopySector !!!\n"); */
+ if (Conv_D_MediaAddr(us, start))
+ return ErrCode;
+
+ while (1) {
+ if (Assign_D_WriteBlock())
+ return ERROR;
+
+ len = Ssfdc.MaxSectors - Media.Sector;
+ if (count > len)
+ bn = len;
+ else
+ bn = count;
+
+ if (Ssfdc_D_CopyBlock(us, bn, buf, Redundant)) {
+ ErrCode = ERR_WriteFault;
+ return ErrCode;
+ }
+
+ Media.Sector = 0x1F;
+ if (Release_D_CopySector(us)) {
+ if (ErrCode == ERR_HwError) {
+ ErrCode = ERR_WriteFault;
+ return ErrCode;
+ }
+ }
+ count -= bn;
+
+ if (count <= 0)
+ break;
+
+ buf += bn * SECTSIZE;
+
+ if (Inc_D_MediaAddr(us))
+ return ErrCode;
+
+ }
+ return NO_ERROR;
+}
+
+/* SmartMedia Physical Format Test Subroutine */
+/* ----- Check_D_MediaFmt() --------------------------------------------- */
+int Check_D_MediaFmt(struct us_data *us)
+{
+ pr_info("Check_D_MediaFmt\n");
+
+ if (!MediaChange)
+ return SMSUCCESS;
+
+ MediaChange = ERROR;
+ SectCopyMode = COMPLETED;
+
+ if (Set_D_PhyFmtValue(us)) {
+ ErrCode = ERR_UnknownMedia;
+ return ERROR;
+ }
+
+ if (Search_D_CIS(us)) {
+ ErrCode = ERR_IllegalFmt;
+ return ERROR;
+ }
+
+ MediaChange = SMSUCCESS;
+ return SMSUCCESS;
+}
+
+/* ----- Release_D_CopySector() ------------------------------------------ */
+static int Release_D_CopySector(struct us_data *us)
+{
+ Log2Phy[Media.Zone][Media.LogBlock] = WriteBlock;
+ Media.PhyBlock = ReadBlock;
+
+ if (Media.PhyBlock == NO_ASSIGN) {
+ Media.PhyBlock = WriteBlock;
+ return SMSUCCESS;
+ }
+
+ Clr_D_Bit(Assign[Media.Zone], Media.PhyBlock);
+ Media.PhyBlock = WriteBlock;
+
+ return SMSUCCESS;
+}
+
+/* SmartMedia Physical Address Control Subroutine */
+/* ----- Conv_D_MediaAddr() --------------------------------------------- */
+static int Conv_D_MediaAddr(struct us_data *us, u32 addr)
+{
+ u32 temp;
+
+ temp = addr / Ssfdc.MaxSectors;
+ Media.Zone = (u8) (temp / Ssfdc.MaxLogBlocks);
+
+ if (Log2Phy[Media.Zone] == NULL) {
+ if (Make_D_LogTable(us)) {
+ ErrCode = ERR_IllegalFmt;
+ return ERROR;
+ }
+ }
+
+ Media.Sector = (u8) (addr % Ssfdc.MaxSectors);
+ Media.LogBlock = (u16) (temp % Ssfdc.MaxLogBlocks);
+
+ if (Media.Zone < Ssfdc.MaxZones) {
+ Clr_D_RedundantData(Redundant);
+ Set_D_LogBlockAddr(Redundant);
+ Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock];
+ return SMSUCCESS;
+ }
+
+ ErrCode = ERR_OutOfLBA;
+ return ERROR;
+}
+
+/* ----- Inc_D_MediaAddr() ---------------------------------------------- */
+static int Inc_D_MediaAddr(struct us_data *us)
+{
+ u16 LogBlock = Media.LogBlock;
+
+ if (++Media.Sector < Ssfdc.MaxSectors)
+ return SMSUCCESS;
+
+ if (Log2Phy[Media.Zone] == NULL) {
+ if (Make_D_LogTable(us)) {
+ ErrCode = ERR_IllegalFmt;
+ return ERROR;
+ }
+ }
+
+ Media.Sector = 0;
+ Media.LogBlock = LogBlock;
+
+ if (++Media.LogBlock < Ssfdc.MaxLogBlocks) {
+ Clr_D_RedundantData(Redundant);
+ Set_D_LogBlockAddr(Redundant);
+ Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock];
+ return SMSUCCESS;
+ }
+
+ Media.LogBlock = 0;
+
+ if (++Media.Zone < Ssfdc.MaxZones) {
+ if (Log2Phy[Media.Zone] == NULL) {
+ if (Make_D_LogTable(us)) {
+ ErrCode = ERR_IllegalFmt;
+ return ERROR;
+ }
+ }
+
+ Media.LogBlock = 0;
+
+ Clr_D_RedundantData(Redundant);
+ Set_D_LogBlockAddr(Redundant);
+ Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock];
+ return SMSUCCESS;
+ }
+
+ Media.Zone = 0;
+ ErrCode = ERR_OutOfLBA;
+
+ return ERROR;
+}
+
+/* SmartMedia Read/Write Subroutine with Retry */
+/* ----- Media_D_ReadOneSect() ------------------------------------------ */
+static int Media_D_ReadOneSect(struct us_data *us, u16 count, u8 *buf)
+{
+ u32 err, retry;
+
+ if (!Read_D_PhyOneSect(us, count, buf))
+ return SMSUCCESS;
+ if (ErrCode == ERR_HwError)
+ return ERROR;
+ if (ErrCode == ERR_DataStatus)
+ return ERROR;
+
+#ifdef RDERR_REASSIGN
+ if (Ssfdc.Attribute & MWP) {
+ if (ErrCode == ERR_CorReadErr)
+ return SMSUCCESS;
+ return ERROR;
+ }
+
+ err = ErrCode;
+ for (retry = 0; retry < 2; retry++) {
+ if (Copy_D_BlockAll(us,
+ (err == ERR_EccReadErr) ? REQ_FAIL : REQ_ERASE)) {
+ if (ErrCode == ERR_HwError)
+ return ERROR;
+ continue;
+ }
+
+ ErrCode = err;
+ if (ErrCode == ERR_CorReadErr)
+ return SMSUCCESS;
+ return ERROR;
+ }
+
+ MediaChange = ERROR;
+#else
+ if (ErrCode == ERR_CorReadErr)
+ return SMSUCCESS;
+#endif
+
+ return ERROR;
+}
+
+/* SmartMedia Physical Sector Data Copy Subroutine */
+/* ----- Copy_D_BlockAll() ---------------------------------------------- */
+static int Copy_D_BlockAll(struct us_data *us, u32 mode)
+{
+ u8 sect;
+
+ sect = Media.Sector;
+
+ if (Assign_D_WriteBlock())
+ return ERROR;
+ if (mode == REQ_FAIL)
+ SectCopyMode = REQ_FAIL;
+
+ for (Media.Sector = 0; Media.Sector < Ssfdc.MaxSectors;
+ Media.Sector++) {
+ if (Copy_D_PhyOneSect(us)) {
+ if (ErrCode == ERR_HwError)
+ return ERROR;
+ if (Release_D_WriteBlock(us))
+ return ERROR;
+
+ ErrCode = ERR_WriteFault;
+ Media.PhyBlock = ReadBlock;
+ Media.Sector = sect;
+
+ return ERROR;
+ }
+ }
+
+ if (Release_D_ReadBlock(us))
+ return ERROR;
+
+ Media.PhyBlock = WriteBlock;
+ Media.Sector = sect;
+ return SMSUCCESS;
+}
+
+/* SmartMedia Physical Block Assign/Release Subroutine */
+/* ----- Assign_D_WriteBlock() ------------------------------------------ */
+static int Assign_D_WriteBlock(void)
+{
+ ReadBlock = Media.PhyBlock;
+
+ for (WriteBlock = AssignStart[Media.Zone];
+ WriteBlock < Ssfdc.MaxBlocks; WriteBlock++) {
+ if (!Chk_D_Bit(Assign[Media.Zone], WriteBlock)) {
+ Set_D_Bit(Assign[Media.Zone], WriteBlock);
+ AssignStart[Media.Zone] = WriteBlock + 1;
+ Media.PhyBlock = WriteBlock;
+ SectCopyMode = REQ_ERASE;
+ return SMSUCCESS;
+ }
+ }
+
+ for (WriteBlock = 0;
+ WriteBlock < AssignStart[Media.Zone]; WriteBlock++) {
+ if (!Chk_D_Bit(Assign[Media.Zone], WriteBlock)) {
+ Set_D_Bit(Assign[Media.Zone], WriteBlock);
+ AssignStart[Media.Zone] = WriteBlock + 1;
+ Media.PhyBlock = WriteBlock;
+ SectCopyMode = REQ_ERASE;
+ return SMSUCCESS;
+ }
+ }
+
+ WriteBlock = NO_ASSIGN;
+ ErrCode = ERR_WriteFault;
+
+ return ERROR;
+}
+
+/* ----- Release_D_ReadBlock() ------------------------------------------ */
+static int Release_D_ReadBlock(struct us_data *us)
+{
+ u32 mode;
+
+ mode = SectCopyMode;
+ SectCopyMode = COMPLETED;
+
+ if (mode == COMPLETED)
+ return SMSUCCESS;
+
+ Log2Phy[Media.Zone][Media.LogBlock] = WriteBlock;
+ Media.PhyBlock = ReadBlock;
+
+ if (Media.PhyBlock == NO_ASSIGN) {
+ Media.PhyBlock = WriteBlock;
+ return SMSUCCESS;
+ }
+
+ if (mode == REQ_ERASE) {
+ if (Erase_D_PhyOneBlock(us)) {
+ if (ErrCode == ERR_HwError)
+ return ERROR;
+ if (MarkFail_D_PhyOneBlock(us))
+ return ERROR;
+ } else
+ Clr_D_Bit(Assign[Media.Zone], Media.PhyBlock);
+ } else if (MarkFail_D_PhyOneBlock(us))
+ return ERROR;
+
+ Media.PhyBlock = WriteBlock;
+ return SMSUCCESS;
+}
+
+/* ----- Release_D_WriteBlock() ----------------------------------------- */
+static int Release_D_WriteBlock(struct us_data *us)
+{
+ SectCopyMode = COMPLETED;
+ Media.PhyBlock = WriteBlock;
+
+ if (MarkFail_D_PhyOneBlock(us))
+ return ERROR;
+
+ Media.PhyBlock = ReadBlock;
+ return SMSUCCESS;
+}
+
+/* SmartMedia Physical Sector Data Copy Subroutine */
+/* ----- Copy_D_PhyOneSect() -------------------------------------------- */
+static int Copy_D_PhyOneSect(struct us_data *us)
+{
+ int i;
+ u32 err, retry;
+
+ /* pr_info("Copy_D_PhyOneSect --- Sector = %x\n", Media.Sector); */
+ if (ReadBlock != NO_ASSIGN) {
+ Media.PhyBlock = ReadBlock;
+ for (retry = 0; retry < 2; retry++) {
+ if (retry != 0) {
+ Ssfdc_D_Reset(us);
+ if (Ssfdc_D_ReadCisSect(us, WorkBuf,
+ WorkRedund)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+
+ if (Check_D_CISdata(WorkBuf, WorkRedund)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ }
+
+ if (Ssfdc_D_ReadSect(us, WorkBuf, WorkRedund)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ if (Check_D_DataStatus(WorkRedund)) {
+ err = ERROR;
+ break;
+ }
+ if (!Check_D_ReadError(WorkRedund)) {
+ err = SMSUCCESS;
+ break;
+ }
+ if (!Check_D_Correct(WorkBuf, WorkRedund)) {
+ err = SMSUCCESS;
+ break;
+ }
+
+ err = ERROR;
+ SectCopyMode = REQ_FAIL;
+ }
+ } else {
+ err = SMSUCCESS;
+ for (i = 0; i < SECTSIZE; i++)
+ WorkBuf[i] = DUMMY_DATA;
+ Clr_D_RedundantData(WorkRedund);
+ }
+
+ Set_D_LogBlockAddr(WorkRedund);
+ if (err == ERROR) {
+ Set_D_RightECC(WorkRedund);
+ Set_D_DataStaus(WorkRedund);
+ }
+
+ Media.PhyBlock = WriteBlock;
+
+ if (Ssfdc_D_WriteSectForCopy(us, WorkBuf, WorkRedund)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ if (Ssfdc_D_CheckStatus()) {
+ ErrCode = ERR_WriteFault;
+ return ERROR;
+ }
+
+ Media.PhyBlock = ReadBlock;
+ return SMSUCCESS;
+}
+
+/* SmartMedia Physical Sector Read/Write/Erase Subroutine */
+/* ----- Read_D_PhyOneSect() -------------------------------------------- */
+static int Read_D_PhyOneSect(struct us_data *us, u16 count, u8 *buf)
+{
+ int i;
+ u32 retry;
+
+ if (Media.PhyBlock == NO_ASSIGN) {
+ for (i = 0; i < SECTSIZE; i++)
+ *buf++ = DUMMY_DATA;
+ return SMSUCCESS;
+ }
+
+ for (retry = 0; retry < 2; retry++) {
+ if (retry != 0) {
+ Ssfdc_D_Reset(us);
+
+ if (Ssfdc_D_ReadCisSect(us, WorkBuf, WorkRedund)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ if (Check_D_CISdata(WorkBuf, WorkRedund)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ }
+
+ if (Ssfdc_D_ReadBlock(us, count, buf, Redundant)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ if (Check_D_DataStatus(Redundant)) {
+ ErrCode = ERR_DataStatus;
+ return ERROR;
+ }
+
+ if (!Check_D_ReadError(Redundant))
+ return SMSUCCESS;
+
+ if (!Check_D_Correct(buf, Redundant)) {
+ ErrCode = ERR_CorReadErr;
+ return ERROR;
+ }
+ }
+
+ ErrCode = ERR_EccReadErr;
+ return ERROR;
+}
+
+/* ----- Erase_D_PhyOneBlock() ------------------------------------------ */
+static int Erase_D_PhyOneBlock(struct us_data *us)
+{
+ if (Ssfdc_D_EraseBlock(us)) {
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ }
+ if (Ssfdc_D_CheckStatus()) {
+ ErrCode = ERR_WriteFault;
+ return ERROR;
+ }
+
+ return SMSUCCESS;
+}
+
+/* SmartMedia Physical Format Check Local Subroutine */
+/* ----- Set_D_PhyFmtValue() -------------------------------------------- */
+static int Set_D_PhyFmtValue(struct us_data *us)
+{
+ if (Set_D_SsfdcModel(us->SM_DeviceID))
+ return ERROR;
+
+ return SMSUCCESS;
+}
+
+/* ----- Search_D_CIS() ------------------------------------------------- */
+static int Search_D_CIS(struct us_data *us)
+{
+ Media.Zone = 0;
+ Media.Sector = 0;
+
+ for (Media.PhyBlock = 0;
+ Media.PhyBlock < (Ssfdc.MaxBlocks - Ssfdc.MaxLogBlocks - 1);
+ Media.PhyBlock++) {
+ if (Ssfdc_D_ReadRedtData(us, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ if (!Check_D_FailBlock(Redundant))
+ break;
+ }
+
+ if (Media.PhyBlock == (Ssfdc.MaxBlocks - Ssfdc.MaxLogBlocks - 1)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ while (Media.Sector < CIS_SEARCH_SECT) {
+ if (Media.Sector) {
+ if (Ssfdc_D_ReadRedtData(us, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+ }
+ if (!Check_D_DataStatus(Redundant)) {
+ if (Ssfdc_D_ReadSect(us, WorkBuf, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ if (Check_D_CISdata(WorkBuf, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ CisArea.PhyBlock = Media.PhyBlock;
+ CisArea.Sector = Media.Sector;
+ Ssfdc_D_Reset(us);
+ return SMSUCCESS;
+ }
+
+ Media.Sector++;
+ }
+
+ Ssfdc_D_Reset(us);
+ return ERROR;
+}
+
+/* ----- Make_D_LogTable() ---------------------------------------------- */
+static int Make_D_LogTable(struct us_data *us)
+{
+ u16 phyblock, logblock;
+
+ if (Log2Phy[Media.Zone] == NULL) {
+ Log2Phy[Media.Zone] = kmalloc(MAX_LOGBLOCK * sizeof(u16),
+ GFP_KERNEL);
+ /* pr_info("ExAllocatePool Zone = %x, Addr = %x\n",
+ Media.Zone, Log2Phy[Media.Zone]); */
+ if (Log2Phy[Media.Zone] == NULL)
+ return ERROR;
+ }
+
+ Media.Sector = 0;
+
+ /* pr_info("Make_D_LogTable --- MediaZone = 0x%x\n",
+ Media.Zone); */
+ for (Media.LogBlock = 0; Media.LogBlock < Ssfdc.MaxLogBlocks;
+ Media.LogBlock++)
+ Log2Phy[Media.Zone][Media.LogBlock] = NO_ASSIGN;
+
+ for (Media.PhyBlock = 0; Media.PhyBlock < (MAX_BLOCKNUM / 8);
+ Media.PhyBlock++)
+ Assign[Media.Zone][Media.PhyBlock] = 0x00;
+
+ for (Media.PhyBlock = 0; Media.PhyBlock < Ssfdc.MaxBlocks;
+ Media.PhyBlock++) {
+ if ((!Media.Zone) && (Media.PhyBlock <= CisArea.PhyBlock)) {
+ Set_D_Bit(Assign[Media.Zone], Media.PhyBlock);
+ continue;
+ }
+
+ if (Ssfdc_D_ReadRedtData(us, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ if (!Check_D_DataBlank(Redundant))
+ continue;
+
+ Set_D_Bit(Assign[Media.Zone], Media.PhyBlock);
+
+ if (Check_D_FailBlock(Redundant))
+ continue;
+
+ if (Load_D_LogBlockAddr(Redundant))
+ continue;
+
+ if (Media.LogBlock >= Ssfdc.MaxLogBlocks)
+ continue;
+
+ if (Log2Phy[Media.Zone][Media.LogBlock] == NO_ASSIGN) {
+ Log2Phy[Media.Zone][Media.LogBlock] = Media.PhyBlock;
+ continue;
+ }
+
+ phyblock = Media.PhyBlock;
+ logblock = Media.LogBlock;
+ Media.Sector = (u8)(Ssfdc.MaxSectors - 1);
+
+ if (Ssfdc_D_ReadRedtData(us, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ if (!Load_D_LogBlockAddr(Redundant) &&
+ (Media.LogBlock == logblock)) {
+ Media.PhyBlock = Log2Phy[Media.Zone][logblock];
+
+ if (Ssfdc_D_ReadRedtData(us, Redundant)) {
+ Ssfdc_D_Reset(us);
+ return ERROR;
+ }
+
+ Media.PhyBlock = phyblock;
+
+ if (!Load_D_LogBlockAddr(Redundant)) {
+ if (Media.LogBlock != logblock) {
+ Media.PhyBlock =
+ Log2Phy[Media.Zone][logblock];
+ Log2Phy[Media.Zone][logblock] =
+ phyblock;
+ }
+ } else {
+ Media.PhyBlock = Log2Phy[Media.Zone][logblock];
+ Log2Phy[Media.Zone][logblock] = phyblock;
+ }
+ }
+
+ Media.Sector = 0;
+ Media.PhyBlock = phyblock;
+
+ AssignStart[Media.Zone] = 0;
+
+ } /* End for (Media.Zone<MAX_ZONENUM) */
+
+ Ssfdc_D_Reset(us);
+ return SMSUCCESS;
+}
+
+/* ----- MarkFail_D_PhyOneBlock() --------------------------------------- */
+static int MarkFail_D_PhyOneBlock(struct us_data *us)
+{
+ u8 sect;
+
+ sect = Media.Sector;
+ Set_D_FailBlock(WorkRedund);
+
+ for (Media.Sector = 0; Media.Sector < Ssfdc.MaxSectors;
+ Media.Sector++) {
+ if (Ssfdc_D_WriteRedtData(us, WorkRedund)) {
+ Ssfdc_D_Reset(us);
+ Media.Sector = sect;
+ ErrCode = ERR_HwError;
+ MediaChange = ERROR;
+ return ERROR;
+ } /* NO Status Check */
+ }
+
+ Ssfdc_D_Reset(us);
+ Media.Sector = sect;
+ return SMSUCCESS;
+}
diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c
new file mode 100644
index 00000000000..e981f14f3bf
--- /dev/null
+++ b/drivers/staging/keucr/smilsub.c
@@ -0,0 +1,679 @@
+#include <linux/slab.h>
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+#include "smcommon.h"
+#include "smil.h"
+
+static u8 _Check_D_DevCode(u8);
+static u32 ErrXDCode;
+static u8 IsSSFDCCompliance;
+static u8 IsXDCompliance;
+
+struct keucr_media_info Ssfdc;
+struct keucr_media_address Media;
+struct keucr_media_area CisArea;
+
+static u8 EccBuf[6];
+
+#define EVEN 0 /* Even Page for 256byte/page */
+#define ODD 1 /* Odd Page for 256byte/page */
+
+
+/* SmartMedia Redundant buffer data Control Subroutine
+ *----- Check_D_DataBlank() --------------------------------------------
+ */
+int Check_D_DataBlank(u8 *redundant)
+{
+ char i;
+
+ for (i = 0; i < REDTSIZE; i++)
+ if (*redundant++ != 0xFF)
+ return ERROR;
+
+ return SMSUCCESS;
+}
+
+/* ----- Check_D_FailBlock() -------------------------------------------- */
+int Check_D_FailBlock(u8 *redundant)
+{
+ redundant += REDT_BLOCK;
+
+ if (*redundant == 0xFF)
+ return SMSUCCESS;
+ if (!*redundant)
+ return ERROR;
+ if (hweight8(*redundant) < 7)
+ return ERROR;
+
+ return SMSUCCESS;
+}
+
+/* ----- Check_D_DataStatus() ------------------------------------------- */
+int Check_D_DataStatus(u8 *redundant)
+{
+ redundant += REDT_DATA;
+
+ if (*redundant == 0xFF)
+ return SMSUCCESS;
+ if (!*redundant) {
+ ErrXDCode = ERR_DataStatus;
+ return ERROR;
+ } else
+ ErrXDCode = NO_ERROR;
+
+ if (hweight8(*redundant) < 5)
+ return ERROR;
+
+ return SMSUCCESS;
+}
+
+/* ----- Load_D_LogBlockAddr() ------------------------------------------ */
+int Load_D_LogBlockAddr(u8 *redundant)
+{
+ u16 addr1, addr2;
+
+ addr1 = (u16)*(redundant + REDT_ADDR1H)*0x0100 +
+ (u16)*(redundant + REDT_ADDR1L);
+ addr2 = (u16)*(redundant + REDT_ADDR2H)*0x0100 +
+ (u16)*(redundant + REDT_ADDR2L);
+
+ if (addr1 == addr2)
+ if ((addr1 & 0xF000) == 0x1000) {
+ Media.LogBlock = (addr1 & 0x0FFF) / 2;
+ return SMSUCCESS;
+ }
+
+ if (hweight16((u16)(addr1^addr2)) != 0x01)
+ return ERROR;
+
+ if ((addr1 & 0xF000) == 0x1000)
+ if (!(hweight16(addr1) & 0x01)) {
+ Media.LogBlock = (addr1 & 0x0FFF) / 2;
+ return SMSUCCESS;
+ }
+
+ if ((addr2 & 0xF000) == 0x1000)
+ if (!(hweight16(addr2) & 0x01)) {
+ Media.LogBlock = (addr2 & 0x0FFF) / 2;
+ return SMSUCCESS;
+ }
+
+ return ERROR;
+}
+
+/* ----- Clr_D_RedundantData() ------------------------------------------ */
+void Clr_D_RedundantData(u8 *redundant)
+{
+ char i;
+
+ for (i = 0; i < REDTSIZE; i++)
+ *(redundant + i) = 0xFF;
+}
+
+/* ----- Set_D_LogBlockAddr() ------------------------------------------- */
+void Set_D_LogBlockAddr(u8 *redundant)
+{
+ u16 addr;
+
+ *(redundant + REDT_BLOCK) = 0xFF;
+ *(redundant + REDT_DATA) = 0xFF;
+ addr = Media.LogBlock*2 + 0x1000;
+
+ if ((hweight16(addr) % 2))
+ addr++;
+
+ *(redundant + REDT_ADDR1H) = *(redundant + REDT_ADDR2H) =
+ (u8)(addr / 0x0100);
+ *(redundant + REDT_ADDR1L) = *(redundant + REDT_ADDR2L) = (u8)addr;
+}
+
+/*----- Set_D_FailBlock() ---------------------------------------------- */
+void Set_D_FailBlock(u8 *redundant)
+{
+ char i;
+
+ for (i = 0; i < REDTSIZE; i++)
+ *redundant++ = (u8)((i == REDT_BLOCK) ? 0xF0 : 0xFF);
+}
+
+/* ----- Set_D_DataStaus() ---------------------------------------------- */
+void Set_D_DataStaus(u8 *redundant)
+{
+ redundant += REDT_DATA;
+ *redundant = 0x00;
+}
+
+/* SmartMedia Function Command Subroutine
+ * 6250 CMD 6
+ */
+/* ----- Ssfdc_D_Reset() ------------------------------------------------ */
+void Ssfdc_D_Reset(struct us_data *us)
+{
+ return;
+}
+
+/* ----- Ssfdc_D_ReadCisSect() ------------------------------------------ */
+int Ssfdc_D_ReadCisSect(struct us_data *us, u8 *buf, u8 *redundant)
+{
+ u8 zone, sector;
+ u16 block;
+
+ zone = Media.Zone; block = Media.PhyBlock; sector = Media.Sector;
+ Media.Zone = 0;
+ Media.PhyBlock = CisArea.PhyBlock;
+ Media.Sector = CisArea.Sector;
+
+ if (Ssfdc_D_ReadSect(us, buf, redundant)) {
+ Media.Zone = zone;
+ Media.PhyBlock = block;
+ Media.Sector = sector;
+ return ERROR;
+ }
+
+ Media.Zone = zone; Media.PhyBlock = block; Media.Sector = sector;
+ return SMSUCCESS;
+}
+
+/* 6250 CMD 1 */
+/* ----- Ssfdc_D_ReadSect() --------------------------------------------- */
+int Ssfdc_D_ReadSect(struct us_data *us, u8 *buf, u8 *redundant)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 addr;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
+
+ /* Read sect data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x02;
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
+ bcb->CDB[2] = Media.Zone / 2;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* Read redundant */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x10;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x03;
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
+ bcb->CDB[2] = Media.Zone / 2;
+ bcb->CDB[8] = 0;
+ bcb->CDB[9] = 1;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, redundant, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- Ssfdc_D_ReadBlock() --------------------------------------------- */
+int Ssfdc_D_ReadBlock(struct us_data *us, u16 count, u8 *buf,
+ u8 *redundant)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 addr;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
+
+ /* Read sect data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200*count;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x02;
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
+ bcb->CDB[2] = Media.Zone / 2;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* Read redundant */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x10;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x03;
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
+ bcb->CDB[2] = Media.Zone / 2;
+ bcb->CDB[8] = 0;
+ bcb->CDB[9] = 1;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, redundant, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+/* ----- Ssfdc_D_CopyBlock() -------------------------------------------- */
+int Ssfdc_D_CopyBlock(struct us_data *us, u16 count, u8 *buf,
+ u8 *redundant)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 ReadAddr, WriteAddr;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ ReadAddr = (u16)Media.Zone*Ssfdc.MaxBlocks + ReadBlock;
+ ReadAddr = ReadAddr*(u16)Ssfdc.MaxSectors;
+ WriteAddr = (u16)Media.Zone*Ssfdc.MaxBlocks + WriteBlock;
+ WriteAddr = WriteAddr*(u16)Ssfdc.MaxSectors;
+
+ /* Write sect data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200*count;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xF0;
+ bcb->CDB[1] = 0x08;
+ bcb->CDB[7] = (u8)WriteAddr;
+ bcb->CDB[6] = (u8)(WriteAddr / 0x0100);
+ bcb->CDB[5] = Media.Zone / 2;
+ bcb->CDB[8] = *(redundant + REDT_ADDR1H);
+ bcb->CDB[9] = *(redundant + REDT_ADDR1L);
+ bcb->CDB[10] = Media.Sector;
+
+ if (ReadBlock != NO_ASSIGN) {
+ bcb->CDB[4] = (u8)ReadAddr;
+ bcb->CDB[3] = (u8)(ReadAddr / 0x0100);
+ bcb->CDB[2] = Media.Zone / 2;
+ } else
+ bcb->CDB[11] = 1;
+
+ result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- Ssfdc_D_WriteSectForCopy() ------------------------------------- */
+int Ssfdc_D_WriteSectForCopy(struct us_data *us, u8 *buf, u8 *redundant)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 addr;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
+
+ /* Write sect data */
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = 0x00;
+ bcb->CDB[0] = 0xF0;
+ bcb->CDB[1] = 0x04;
+ bcb->CDB[7] = (u8)addr;
+ bcb->CDB[6] = (u8)(addr / 0x0100);
+ bcb->CDB[5] = Media.Zone / 2;
+ bcb->CDB[8] = *(redundant + REDT_ADDR1H);
+ bcb->CDB[9] = *(redundant + REDT_ADDR1L);
+
+ result = ENE_SendScsiCmd(us, FDIR_WRITE, buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* 6250 CMD 5 */
+/* ----- Ssfdc_D_EraseBlock() ------------------------------------------- */
+int Ssfdc_D_EraseBlock(struct us_data *us)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 addr;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF2;
+ bcb->CDB[1] = 0x06;
+ bcb->CDB[7] = (u8)addr;
+ bcb->CDB[6] = (u8)(addr / 0x0100);
+ bcb->CDB[5] = Media.Zone / 2;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* 6250 CMD 2 */
+/*----- Ssfdc_D_ReadRedtData() ----------------------------------------- */
+int Ssfdc_D_ReadRedtData(struct us_data *us, u8 *redundant)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 addr;
+ u8 *buf;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x10;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+ bcb->CDB[1] = 0x03;
+ bcb->CDB[4] = (u8)addr;
+ bcb->CDB[3] = (u8)(addr / 0x0100);
+ bcb->CDB[2] = Media.Zone / 2;
+ bcb->CDB[8] = 0;
+ bcb->CDB[9] = 1;
+
+ buf = kmalloc(0x10, GFP_KERNEL);
+ result = ENE_SendScsiCmd(us, FDIR_READ, buf, 0);
+ memcpy(redundant, buf, 0x10);
+ kfree(buf);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* 6250 CMD 4 */
+/* ----- Ssfdc_D_WriteRedtData() ---------------------------------------- */
+int Ssfdc_D_WriteRedtData(struct us_data *us, u8 *redundant)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ u16 addr;
+
+ result = ENE_LoadBinCode(us, SM_RW_PATTERN);
+ if (result != USB_STOR_XFER_GOOD) {
+ dev_err(&us->pusb_dev->dev,
+ "Failed to load SmartMedia read/write code\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ addr = (u16)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock;
+ addr = addr*(u16)Ssfdc.MaxSectors + Media.Sector;
+
+ memset(bcb, 0, sizeof(struct bulk_cb_wrap));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x10;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF2;
+ bcb->CDB[1] = 0x05;
+ bcb->CDB[7] = (u8)addr;
+ bcb->CDB[6] = (u8)(addr / 0x0100);
+ bcb->CDB[5] = Media.Zone / 2;
+ bcb->CDB[8] = *(redundant + REDT_ADDR1H);
+ bcb->CDB[9] = *(redundant + REDT_ADDR1L);
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- Ssfdc_D_CheckStatus() ------------------------------------------ */
+int Ssfdc_D_CheckStatus(void)
+{
+ return SMSUCCESS;
+}
+
+
+
+/* SmartMedia ID Code Check & Mode Set Subroutine
+ * ----- Set_D_SsfdcModel() ---------------------------------------------
+ */
+int Set_D_SsfdcModel(u8 dcode)
+{
+ switch (_Check_D_DevCode(dcode)) {
+ case SSFDC1MB:
+ Ssfdc.Model = SSFDC1MB;
+ Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS256;
+ Ssfdc.MaxZones = 1;
+ Ssfdc.MaxBlocks = 256;
+ Ssfdc.MaxLogBlocks = 250;
+ Ssfdc.MaxSectors = 8;
+ break;
+ case SSFDC2MB:
+ Ssfdc.Model = SSFDC2MB;
+ Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS256;
+ Ssfdc.MaxZones = 1;
+ Ssfdc.MaxBlocks = 512;
+ Ssfdc.MaxLogBlocks = 500;
+ Ssfdc.MaxSectors = 8;
+ break;
+ case SSFDC4MB:
+ Ssfdc.Model = SSFDC4MB;
+ Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS512;
+ Ssfdc.MaxZones = 1;
+ Ssfdc.MaxBlocks = 512;
+ Ssfdc.MaxLogBlocks = 500;
+ Ssfdc.MaxSectors = 16;
+ break;
+ case SSFDC8MB:
+ Ssfdc.Model = SSFDC8MB;
+ Ssfdc.Attribute = FLASH | AD3CYC | BS16 | PS512;
+ Ssfdc.MaxZones = 1;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 16;
+ break;
+ case SSFDC16MB:
+ Ssfdc.Model = SSFDC16MB;
+ Ssfdc.Attribute = FLASH | AD3CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 1;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC32MB:
+ Ssfdc.Model = SSFDC32MB;
+ Ssfdc.Attribute = FLASH | AD3CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 2;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC64MB:
+ Ssfdc.Model = SSFDC64MB;
+ Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 4;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC128MB:
+ Ssfdc.Model = SSFDC128MB;
+ Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 8;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC256MB:
+ Ssfdc.Model = SSFDC256MB;
+ Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 16;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC512MB:
+ Ssfdc.Model = SSFDC512MB;
+ Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 32;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC1GB:
+ Ssfdc.Model = SSFDC1GB;
+ Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 64;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ case SSFDC2GB:
+ Ssfdc.Model = SSFDC2GB;
+ Ssfdc.Attribute = FLASH | AD4CYC | BS32 | PS512;
+ Ssfdc.MaxZones = 128;
+ Ssfdc.MaxBlocks = 1024;
+ Ssfdc.MaxLogBlocks = 1000;
+ Ssfdc.MaxSectors = 32;
+ break;
+ default:
+ Ssfdc.Model = NOSSFDC;
+ return ERROR;
+ }
+
+ return SMSUCCESS;
+}
+
+/* ----- _Check_D_DevCode() --------------------------------------------- */
+static u8 _Check_D_DevCode(u8 dcode)
+{
+ switch (dcode) {
+ case 0x6E:
+ case 0xE8:
+ case 0xEC: return SSFDC1MB; /* 8Mbit (1M) NAND */
+ case 0x64:
+ case 0xEA: return SSFDC2MB; /* 16Mbit (2M) NAND */
+ case 0x6B:
+ case 0xE3:
+ case 0xE5: return SSFDC4MB; /* 32Mbit (4M) NAND */
+ case 0xE6: return SSFDC8MB; /* 64Mbit (8M) NAND */
+ case 0x73: return SSFDC16MB; /* 128Mbit (16M)NAND */
+ case 0x75: return SSFDC32MB; /* 256Mbit (32M)NAND */
+ case 0x76: return SSFDC64MB; /* 512Mbit (64M)NAND */
+ case 0x79: return SSFDC128MB; /* 1Gbit(128M)NAND */
+ case 0x71: return SSFDC256MB;
+ case 0xDC: return SSFDC512MB;
+ case 0xD3: return SSFDC1GB;
+ case 0xD5: return SSFDC2GB;
+ default: return NOSSFDC;
+ }
+}
+
+
+
+
+/* SmartMedia ECC Control Subroutine
+ * ----- Check_D_ReadError() ----------------------------------------------
+ */
+int Check_D_ReadError(u8 *redundant)
+{
+ return SMSUCCESS;
+}
+
+/* ----- Check_D_Correct() ---------------------------------------------- */
+int Check_D_Correct(u8 *buf, u8 *redundant)
+{
+ return SMSUCCESS;
+}
+
+/* ----- Check_D_CISdata() ---------------------------------------------- */
+int Check_D_CISdata(u8 *buf, u8 *redundant)
+{
+ u8 cis[] = {0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02,
+ 0xDF, 0x01, 0x20};
+
+ int cis_len = sizeof(cis);
+
+ if (!IsSSFDCCompliance && !IsXDCompliance)
+ return SMSUCCESS;
+
+ if (!memcmp(redundant + 0x0D, EccBuf, 3))
+ return memcmp(buf, cis, cis_len);
+
+ if (!_Correct_D_SwECC(buf, redundant + 0x0D, EccBuf))
+ return memcmp(buf, cis, cis_len);
+
+ buf += 0x100;
+ if (!memcmp(redundant + 0x08, EccBuf + 0x03, 3))
+ return memcmp(buf, cis, cis_len);
+
+ if (!_Correct_D_SwECC(buf, redundant + 0x08, EccBuf + 0x03))
+ return memcmp(buf, cis, cis_len);
+
+ return ERROR;
+}
+
+/* ----- Set_D_RightECC() ---------------------------------------------- */
+void Set_D_RightECC(u8 *redundant)
+{
+ /* Driver ECC Check */
+ return;
+}
+
+
diff --git a/drivers/staging/keucr/smscsi.c b/drivers/staging/keucr/smscsi.c
new file mode 100644
index 00000000000..20858f6777c
--- /dev/null
+++ b/drivers/staging/keucr/smscsi.c
@@ -0,0 +1,194 @@
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+#include "smil.h"
+
+static int SM_SCSI_Test_Unit_Ready(struct us_data *us, struct scsi_cmnd *srb);
+static int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb);
+static int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb);
+static int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb);
+static int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb);
+static int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb);
+
+/* ----- SM_SCSIIrp() -------------------------------------------------- */
+int SM_SCSIIrp(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result;
+
+ us->SrbStatus = SS_SUCCESS;
+ switch (srb->cmnd[0]) {
+ case TEST_UNIT_READY:
+ result = SM_SCSI_Test_Unit_Ready(us, srb);
+ break; /* 0x00 */
+ case INQUIRY:
+ result = SM_SCSI_Inquiry(us, srb);
+ break; /* 0x12 */
+ case MODE_SENSE:
+ result = SM_SCSI_Mode_Sense(us, srb);
+ break; /* 0x1A */
+ case READ_CAPACITY:
+ result = SM_SCSI_Read_Capacity(us, srb);
+ break; /* 0x25 */
+ case READ_10:
+ result = SM_SCSI_Read(us, srb);
+ break; /* 0x28 */
+ case WRITE_10:
+ result = SM_SCSI_Write(us, srb);
+ break; /* 0x2A */
+
+ default:
+ us->SrbStatus = SS_ILLEGAL_REQUEST;
+ result = USB_STOR_TRANSPORT_FAILED;
+ break;
+ }
+ return result;
+}
+
+/* ----- SM_SCSI_Test_Unit_Ready() ------------------------------------- */
+static int SM_SCSI_Test_Unit_Ready(struct us_data *us, struct scsi_cmnd *srb)
+{
+ if (us->SM_Status.Insert && us->SM_Status.Ready)
+ return USB_STOR_TRANSPORT_GOOD;
+ else {
+ ENE_SMInit(us);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- SM_SCSI_Inquiry() --------------------------------------------- */
+static int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb)
+{
+ u8 data_ptr[36] = {0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00,
+ 0x55, 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20,
+ 0x20, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65,
+ 0x61, 0x64, 0x65, 0x72, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30};
+
+ usb_stor_set_xfer_buf(us, data_ptr, 36, srb, TO_XFER_BUF);
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+/* ----- SM_SCSI_Mode_Sense() ------------------------------------------ */
+static int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb)
+{
+ u8 mediaNoWP[12] = {0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00};
+ u8 mediaWP[12] = {0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
+ 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00};
+
+ if (us->SM_Status.WtP)
+ usb_stor_set_xfer_buf(us, mediaWP, 12, srb, TO_XFER_BUF);
+ else
+ usb_stor_set_xfer_buf(us, mediaNoWP, 12, srb, TO_XFER_BUF);
+
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- SM_SCSI_Read_Capacity() --------------------------------------- */
+static int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb)
+{
+ unsigned int offset = 0;
+ struct scatterlist *sg = NULL;
+ u32 bl_num;
+ u16 bl_len;
+ u8 buf[8];
+
+ dev_dbg(&us->pusb_dev->dev, "SM_SCSI_Read_Capacity\n");
+
+ bl_len = 0x200;
+ bl_num = Ssfdc.MaxLogBlocks * Ssfdc.MaxSectors * Ssfdc.MaxZones - 1;
+
+ us->bl_num = bl_num;
+ dev_dbg(&us->pusb_dev->dev, "bl_len = %x\n", bl_len);
+ dev_dbg(&us->pusb_dev->dev, "bl_num = %x\n", bl_num);
+
+ buf[0] = (bl_num >> 24) & 0xff;
+ buf[1] = (bl_num >> 16) & 0xff;
+ buf[2] = (bl_num >> 8) & 0xff;
+ buf[3] = (bl_num >> 0) & 0xff;
+ buf[4] = (bl_len >> 24) & 0xff;
+ buf[5] = (bl_len >> 16) & 0xff;
+ buf[6] = (bl_len >> 8) & 0xff;
+ buf[7] = (bl_len >> 0) & 0xff;
+
+ usb_stor_access_xfer_buf(us, buf, 8, srb, &sg, &offset, TO_XFER_BUF);
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- SM_SCSI_Read() -------------------------------------------------- */
+static int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result = 0;
+ u8 *Cdb = srb->cmnd;
+ u32 bn = ((Cdb[2] << 24) & 0xff000000) |
+ ((Cdb[3] << 16) & 0x00ff0000) |
+ ((Cdb[4] << 8) & 0x0000ff00) |
+ ((Cdb[5] << 0) & 0x000000ff);
+ u16 blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
+ u32 blenByte = blen * 0x200;
+ void *buf;
+
+
+ if (bn > us->bl_num)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ buf = kmalloc(blenByte, GFP_KERNEL);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ result = Media_D_ReadSector(us, bn, blen, buf);
+ usb_stor_set_xfer_buf(us, buf, blenByte, srb, TO_XFER_BUF);
+ kfree(buf);
+
+ if (!result)
+ return USB_STOR_TRANSPORT_GOOD;
+ else
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+/* ----- SM_SCSI_Write() -------------------------------------------------- */
+static int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb)
+{
+ int result = 0;
+ u8 *Cdb = srb->cmnd;
+ u32 bn = ((Cdb[2] << 24) & 0xff000000) |
+ ((Cdb[3] << 16) & 0x00ff0000) |
+ ((Cdb[4] << 8) & 0x0000ff00) |
+ ((Cdb[5] << 0) & 0x000000ff);
+ u16 blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff);
+ u32 blenByte = blen * 0x200;
+ void *buf;
+
+
+ if (bn > us->bl_num)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ buf = kmalloc(blenByte, GFP_KERNEL);
+ if (buf == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+ usb_stor_set_xfer_buf(us, buf, blenByte, srb, FROM_XFER_BUF);
+ result = Media_D_CopySector(us, bn, blen, buf);
+ kfree(buf);
+
+ if (!result)
+ return USB_STOR_TRANSPORT_GOOD;
+ else
+ return USB_STOR_TRANSPORT_ERROR;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
diff --git a/drivers/staging/keucr/transport.c b/drivers/staging/keucr/transport.c
new file mode 100644
index 00000000000..5e59525271f
--- /dev/null
+++ b/drivers/staging/keucr/transport.c
@@ -0,0 +1,865 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "transport.h"
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+/*
+ * usb_stor_blocking_completion()
+ */
+static void usb_stor_blocking_completion(struct urb *urb)
+{
+ struct completion *urb_done_ptr = urb->context;
+
+ /* pr_info("transport --- usb_stor_blocking_completion\n"); */
+ complete(urb_done_ptr);
+}
+
+/*
+ * usb_stor_msg_common()
+ */
+static int usb_stor_msg_common(struct us_data *us, int timeout)
+{
+ struct completion urb_done;
+ long timeleft;
+ int status;
+
+ /* pr_info("transport --- usb_stor_msg_common\n"); */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+ return -EIO;
+
+ init_completion(&urb_done);
+
+ us->current_urb->context = &urb_done;
+ us->current_urb->actual_length = 0;
+ us->current_urb->error_count = 0;
+ us->current_urb->status = 0;
+
+ us->current_urb->transfer_flags = 0;
+ if (us->current_urb->transfer_buffer == us->iobuf)
+ us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ us->current_urb->transfer_dma = us->iobuf_dma;
+ us->current_urb->setup_dma = us->cr_dma;
+
+ status = usb_submit_urb(us->current_urb, GFP_NOIO);
+ if (status)
+ return status;
+
+ set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
+ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
+ /* pr_info("-- cancelling URB\n"); */
+ usb_unlink_urb(us->current_urb);
+ }
+ }
+
+ timeleft = wait_for_completion_interruptible_timeout(&urb_done,
+ timeout ? : MAX_SCHEDULE_TIMEOUT);
+ clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);
+
+ if (timeleft <= 0) {
+ /* pr_info("%s -- cancelling URB\n",
+ timeleft == 0 ? "Timeout" : "Signal"); */
+ usb_kill_urb(us->current_urb);
+ }
+
+ return us->current_urb->status;
+}
+
+/*
+ * usb_stor_print_cmd():
+ */
+static void usb_stor_print_cmd(struct us_data *us, struct scsi_cmnd *srb)
+{
+ u8 *Cdb = srb->cmnd;
+ u32 cmd = Cdb[0];
+
+ switch (cmd) {
+ case TEST_UNIT_READY:
+ break;
+ case INQUIRY:
+ dev_dbg(&us->pusb_dev->dev,
+ "scsi cmd %X --- SCSIOP_INQUIRY\n", cmd);
+ break;
+ case MODE_SENSE:
+ dev_dbg(&us->pusb_dev->dev,
+ "scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd);
+ break;
+ case START_STOP:
+ dev_dbg(&us->pusb_dev->dev,
+ "scsi cmd %X --- SCSIOP_START_STOP\n", cmd);
+ break;
+ case READ_CAPACITY:
+ dev_dbg(&us->pusb_dev->dev,
+ "scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd);
+ break;
+ case READ_10:
+ break;
+ case WRITE_10:
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ dev_dbg(&us->pusb_dev->dev,
+ "scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd);
+ break;
+ default:
+ dev_dbg(&us->pusb_dev->dev, "scsi cmd %X --- Other cmd\n", cmd);
+ break;
+ }
+}
+
+/*
+ * usb_stor_control_msg()
+ */
+int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size, int timeout)
+{
+ int status;
+
+ /* pr_info("transport --- usb_stor_control_msg\n"); */
+
+ /* fill in the devrequest structure */
+ us->cr->bRequestType = requesttype;
+ us->cr->bRequest = request;
+ us->cr->wValue = cpu_to_le16(value);
+ us->cr->wIndex = cpu_to_le16(index);
+ us->cr->wLength = cpu_to_le16(size);
+
+ /* fill and submit the URB */
+ usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe,
+ (unsigned char *) us->cr, data, size,
+ usb_stor_blocking_completion, NULL);
+ status = usb_stor_msg_common(us, timeout);
+
+ /* return the actual length of the data transferred if no error */
+ if (status == 0)
+ status = us->current_urb->actual_length;
+ return status;
+}
+
+/*
+ * usb_stor_clear_halt()
+ */
+int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
+{
+ int result;
+ int endp = usb_pipeendpoint(pipe);
+
+ /* pr_info("transport --- usb_stor_clear_halt\n"); */
+ if (usb_pipein(pipe))
+ endp |= USB_DIR_IN;
+
+ result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+ USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
+ USB_ENDPOINT_HALT, endp,
+ NULL, 0, 3*HZ);
+
+ /* reset the endpoint toggle */
+ if (result >= 0)
+ /* usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), 0); */
+ usb_reset_endpoint(us->pusb_dev, endp);
+
+ return result;
+}
+
+/*
+ * interpret_urb_result()
+ */
+static int interpret_urb_result(struct us_data *us, unsigned int pipe,
+ unsigned int length, int result, unsigned int partial)
+{
+ /* pr_info("transport --- interpret_urb_result\n"); */
+ switch (result) {
+ /* no error code; did we send all the data? */
+ case 0:
+ if (partial != length) {
+ /* pr_info("-- short transfer\n"); */
+ return USB_STOR_XFER_SHORT;
+ }
+ /* pr_info("-- transfer complete\n"); */
+ return USB_STOR_XFER_GOOD;
+ case -EPIPE:
+ if (usb_pipecontrol(pipe)) {
+ /* pr_info("-- stall on control pipe\n"); */
+ return USB_STOR_XFER_STALLED;
+ }
+ /* pr_info("clearing endpoint halt for pipe 0x%x\n", pipe); */
+ if (usb_stor_clear_halt(us, pipe) < 0)
+ return USB_STOR_XFER_ERROR;
+ return USB_STOR_XFER_STALLED;
+ case -EOVERFLOW:
+ /* pr_info("-- babble\n"); */
+ return USB_STOR_XFER_LONG;
+ case -ECONNRESET:
+ /* pr_info("-- transfer cancelled\n"); */
+ return USB_STOR_XFER_ERROR;
+ case -EREMOTEIO:
+ /* pr_info("-- short read transfer\n"); */
+ return USB_STOR_XFER_SHORT;
+ case -EIO:
+ /* pr_info("-- abort or disconnect in progress\n"); */
+ return USB_STOR_XFER_ERROR;
+ default:
+ /* pr_info("-- unknown error\n"); */
+ return USB_STOR_XFER_ERROR;
+ }
+}
+
+/*
+ * usb_stor_bulk_transfer_buf()
+ */
+int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+ void *buf, unsigned int length, unsigned int *act_len)
+{
+ int result;
+
+ /* pr_info("transport --- usb_stor_bulk_transfer_buf\n"); */
+
+ /* fill and submit the URB */
+ usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf,
+ length, usb_stor_blocking_completion, NULL);
+ result = usb_stor_msg_common(us, 0);
+
+ /* store the actual length of the data transferred */
+ if (act_len)
+ *act_len = us->current_urb->actual_length;
+
+ return interpret_urb_result(us, pipe, length, result,
+ us->current_urb->actual_length);
+}
+
+/*
+ * usb_stor_bulk_transfer_sglist()
+ */
+static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
+ struct scatterlist *sg, int num_sg, unsigned int length,
+ unsigned int *act_len)
+{
+ int result;
+
+ /* pr_info("transport --- usb_stor_bulk_transfer_sglist\n"); */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags))
+ return USB_STOR_XFER_ERROR;
+
+ /* initialize the scatter-gather request block */
+ result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
+ sg, num_sg, length, GFP_NOIO);
+ if (result) {
+ /* pr_info("usb_sg_init returned %d\n", result); */
+ return USB_STOR_XFER_ERROR;
+ }
+
+ /* since the block has been initialized successfully,
+ it's now okay to cancel it */
+ set_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
+
+ /* did an abort/disconnect occur during the submission? */
+ if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {
+ /* cancel the request, if it hasn't been cancelled already */
+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
+ /* pr_info("-- cancelling sg request\n"); */
+ usb_sg_cancel(&us->current_sg);
+ }
+ }
+
+ /* wait for the completion of the transfer */
+ usb_sg_wait(&us->current_sg);
+ clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);
+
+ result = us->current_sg.status;
+ if (act_len)
+ *act_len = us->current_sg.bytes;
+
+ return interpret_urb_result(us, pipe, length,
+ result, us->current_sg.bytes);
+}
+
+/*
+ * usb_stor_bulk_srb()
+ */
+int usb_stor_bulk_srb(struct us_data *us, unsigned int pipe,
+ struct scsi_cmnd *srb)
+{
+ unsigned int partial;
+ int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb),
+ scsi_sg_count(srb), scsi_bufflen(srb),
+ &partial);
+
+ scsi_set_resid(srb, scsi_bufflen(srb) - partial);
+ return result;
+}
+
+/*
+ * usb_stor_bulk_transfer_sg()
+ */
+int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
+ void *buf, unsigned int length_left, int use_sg, int *residual)
+{
+ int result;
+ unsigned int partial;
+
+ /* pr_info("transport --- usb_stor_bulk_transfer_sg\n"); */
+ /* are we scatter-gathering? */
+ if (use_sg) {
+ /* use the usb core scatter-gather primitives */
+ result = usb_stor_bulk_transfer_sglist(us, pipe,
+ (struct scatterlist *) buf, use_sg,
+ length_left, &partial);
+ length_left -= partial;
+ } else {
+ /* no scatter-gather, just make the request */
+ result = usb_stor_bulk_transfer_buf(us, pipe, buf,
+ length_left, &partial);
+ length_left -= partial;
+ }
+
+ /* store the residual and return the error code */
+ if (residual)
+ *residual = length_left;
+ return result;
+}
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+/*
+ * usb_stor_invoke_transport()
+ */
+void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int need_auto_sense;
+ int result;
+
+ /* pr_info("transport --- usb_stor_invoke_transport\n"); */
+ usb_stor_print_cmd(us, srb);
+ /* send the command to the transport layer */
+ scsi_set_resid(srb, 0);
+ result = us->transport(srb, us); /* usb_stor_Bulk_transport; */
+
+ /* if the command gets aborted by the higher layers,
+ we need to short-circuit all other processing */
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ /* pr_info("-- command was aborted\n"); */
+ srb->result = DID_ABORT << 16;
+ goto Handle_Errors;
+ }
+
+ /* if there is a transport error, reset and don't auto-sense */
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ /* pr_info("-- transport indicates error, resetting\n"); */
+ srb->result = DID_ERROR << 16;
+ goto Handle_Errors;
+ }
+
+ /* if the transport provided its own sense data, don't auto-sense */
+ if (result == USB_STOR_TRANSPORT_NO_SENSE) {
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ return;
+ }
+
+ srb->result = SAM_STAT_GOOD;
+
+ /* Determine if we need to auto-sense */
+ need_auto_sense = 0;
+
+ if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) &&
+ srb->sc_data_direction != DMA_FROM_DEVICE) {
+ /* pr_info("-- CB transport device requiring auto-sense\n"); */
+ need_auto_sense = 1;
+ }
+
+ if (result == USB_STOR_TRANSPORT_FAILED) {
+ /* pr_info("-- transport indicates command failure\n"); */
+ need_auto_sense = 1;
+ }
+
+ /* Now, if we need to do the auto-sense, let's do it */
+ if (need_auto_sense) {
+ int temp_result;
+ struct scsi_eh_save ses;
+
+ pr_info("Issuing auto-REQUEST_SENSE\n");
+
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
+
+ /* we must do the protocol translation here */
+ if (us->subclass == USB_SC_RBC ||
+ us->subclass == USB_SC_SCSI ||
+ us->subclass == USB_SC_CYP_ATACB) {
+ srb->cmd_len = 6;
+ } else {
+ srb->cmd_len = 12;
+ }
+ /* issue the auto-sense command */
+ scsi_set_resid(srb, 0);
+ temp_result = us->transport(us->srb, us);
+
+ /* let's clean up right away */
+ scsi_eh_restore_cmnd(srb, &ses);
+
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ /* pr_info("-- auto-sense aborted\n"); */
+ srb->result = DID_ABORT << 16;
+ goto Handle_Errors;
+ }
+ if (temp_result != USB_STOR_TRANSPORT_GOOD) {
+ /* pr_info("-- auto-sense failure\n"); */
+ srb->result = DID_ERROR << 16;
+ if (!(us->fflags & US_FL_SCM_MULT_TARG))
+ goto Handle_Errors;
+ return;
+ }
+
+ /* set the result so the higher layers expect this data */
+ srb->result = SAM_STAT_CHECK_CONDITION;
+
+ if (result == USB_STOR_TRANSPORT_GOOD &&
+ (srb->sense_buffer[2] & 0xaf) == 0 &&
+ srb->sense_buffer[12] == 0 &&
+ srb->sense_buffer[13] == 0) {
+ srb->result = SAM_STAT_GOOD;
+ srb->sense_buffer[0] = 0x0;
+ }
+ }
+
+ /* Did we transfer less than the minimum amount required? */
+ if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) -
+ scsi_get_resid(srb) < srb->underflow)
+ srb->result = (DID_ERROR << 16);
+ /* v02 | (SUGGEST_RETRY << 24); */
+
+ return;
+
+Handle_Errors:
+ scsi_lock(us_to_host(us));
+ set_bit(US_FLIDX_RESETTING, &us->dflags);
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
+ scsi_unlock(us_to_host(us));
+
+ mutex_unlock(&us->dev_mutex);
+ result = usb_stor_port_reset(us);
+ mutex_lock(&us->dev_mutex);
+
+ if (result < 0) {
+ scsi_lock(us_to_host(us));
+ usb_stor_report_device_reset(us);
+ scsi_unlock(us_to_host(us));
+ us->transport_reset(us);
+ }
+ clear_bit(US_FLIDX_RESETTING, &us->dflags);
+}
+
+/*
+ * ENE_stor_invoke_transport()
+ */
+void ENE_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int result = 0;
+
+ /* pr_info("transport --- ENE_stor_invoke_transport\n"); */
+ usb_stor_print_cmd(us, srb);
+ /* send the command to the transport layer */
+ scsi_set_resid(srb, 0);
+ if (!(us->SM_Status.Ready))
+ result = ENE_InitMedia(us);
+
+ if (us->Power_IsResum == true) {
+ result = ENE_InitMedia(us);
+ us->Power_IsResum = false;
+ }
+
+ if (us->SM_Status.Ready)
+ result = SM_SCSIIrp(us, srb);
+
+ /* if the command gets aborted by the higher layers,
+ we need to short-circuit all other processing */
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ /* pr_info("-- command was aborted\n"); */
+ srb->result = DID_ABORT << 16;
+ goto Handle_Errors;
+ }
+
+ /* if there is a transport error, reset and don't auto-sense */
+ if (result == USB_STOR_TRANSPORT_ERROR) {
+ /* pr_info("-- transport indicates error, resetting\n"); */
+ srb->result = DID_ERROR << 16;
+ goto Handle_Errors;
+ }
+
+ /* if the transport provided its own sense data, don't auto-sense */
+ if (result == USB_STOR_TRANSPORT_NO_SENSE) {
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ return;
+ }
+
+ srb->result = SAM_STAT_GOOD;
+ if (result == USB_STOR_TRANSPORT_FAILED) {
+ /* pr_info("-- transport indicates command failure\n"); */
+ /* need_auto_sense = 1; */
+ BuildSenseBuffer(srb, us->SrbStatus);
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ }
+
+ /* Did we transfer less than the minimum amount required? */
+ if (srb->result == SAM_STAT_GOOD && scsi_bufflen(srb) -
+ scsi_get_resid(srb) < srb->underflow)
+ srb->result = (DID_ERROR << 16);
+ /* v02 | (SUGGEST_RETRY << 24); */
+
+ return;
+
+Handle_Errors:
+ scsi_lock(us_to_host(us));
+ set_bit(US_FLIDX_RESETTING, &us->dflags);
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
+ scsi_unlock(us_to_host(us));
+
+ mutex_unlock(&us->dev_mutex);
+ result = usb_stor_port_reset(us);
+ mutex_lock(&us->dev_mutex);
+
+ if (result < 0) {
+ scsi_lock(us_to_host(us));
+ usb_stor_report_device_reset(us);
+ scsi_unlock(us_to_host(us));
+ us->transport_reset(us);
+ }
+ clear_bit(US_FLIDX_RESETTING, &us->dflags);
+}
+
+/*
+ * BuildSenseBuffer()
+ */
+void BuildSenseBuffer(struct scsi_cmnd *srb, int SrbStatus)
+{
+ u8 *buf = srb->sense_buffer;
+ u8 asc;
+
+ pr_info("transport --- BuildSenseBuffer\n");
+ switch (SrbStatus) {
+ case SS_NOT_READY:
+ asc = 0x3a;
+ break; /* sense key = 0x02 */
+ case SS_MEDIUM_ERR:
+ asc = 0x0c;
+ break; /* sense key = 0x03 */
+ case SS_ILLEGAL_REQUEST:
+ asc = 0x20;
+ break; /* sense key = 0x05 */
+ default:
+ asc = 0x00;
+ break; /* ?? */
+ }
+
+ memset(buf, 0, 18);
+ buf[0x00] = 0xf0;
+ buf[0x02] = SrbStatus;
+ buf[0x07] = 0x0b;
+ buf[0x0c] = asc;
+}
+
+/*
+ * usb_stor_stop_transport()
+ */
+void usb_stor_stop_transport(struct us_data *us)
+{
+ /* pr_info("transport --- usb_stor_stop_transport\n"); */
+
+ if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {
+ /* pr_info("-- cancelling URB\n"); */
+ usb_unlink_urb(us->current_urb);
+ }
+
+ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) {
+ /* pr_info("-- cancelling sg request\n"); */
+ usb_sg_cancel(&us->current_sg);
+ }
+}
+
+/*
+ * usb_stor_Bulk_max_lun()
+ */
+int usb_stor_Bulk_max_lun(struct us_data *us)
+{
+ int result;
+
+ /* pr_info("transport --- usb_stor_Bulk_max_lun\n"); */
+ /* issue the command */
+ us->iobuf[0] = 0;
+ result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
+ US_BULK_GET_MAX_LUN,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ 0, us->ifnum, us->iobuf, 1, HZ);
+
+ /* pr_info("GetMaxLUN command result is %d, data is %d\n",
+ result, us->iobuf[0]); */
+
+ /* if we have a successful request, return the result */
+ if (result > 0)
+ return us->iobuf[0];
+
+ return 0;
+}
+
+/*
+ * usb_stor_Bulk_transport()
+ */
+int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
+ unsigned int transfer_length = scsi_bufflen(srb);
+ unsigned int residue;
+ int result;
+ int fake_sense = 0;
+ unsigned int cswlen;
+ unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+
+ /* pr_info("transport --- usb_stor_Bulk_transport\n"); */
+ /* Take care of BULK32 devices; set extra byte to 0 */
+ if (unlikely(us->fflags & US_FL_BULK32)) {
+ cbwlen = 32;
+ us->iobuf[31] = 0;
+ }
+
+ /* set up the command wrapper */
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = cpu_to_le32(transfer_length);
+ bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+ bcb->Tag = ++us->tag;
+ bcb->Lun = srb->device->lun;
+ if (us->fflags & US_FL_SCM_MULT_TARG)
+ bcb->Lun |= srb->device->id << 4;
+ bcb->Length = srb->cmd_len;
+
+ /* copy the command payload */
+ memset(bcb->CDB, 0, sizeof(bcb->CDB));
+ memcpy(bcb->CDB, srb->cmnd, bcb->Length);
+
+ /* send command */
+ /* send it to out endpoint */
+ /* pr_info("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
+ le32_to_cpu(bcb->Signature), bcb->Tag,
+ le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
+ (bcb->Lun >> 4), (bcb->Lun & 0x0F),
+ bcb->Length); */
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ bcb, cbwlen, NULL);
+ /* pr_info("Bulk command transfer result=%d\n", result); */
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (unlikely(us->fflags & US_FL_GO_SLOW))
+ udelay(125);
+
+ /* R/W data */
+ if (transfer_length) {
+ unsigned int pipe;
+
+ if (srb->sc_data_direction == DMA_FROM_DEVICE)
+ pipe = us->recv_bulk_pipe;
+ else
+ pipe = us->send_bulk_pipe;
+
+ result = usb_stor_bulk_srb(us, pipe, srb);
+ /* pr_info("Bulk data transfer result 0x%x\n", result); */
+ if (result == USB_STOR_XFER_ERROR)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ if (result == USB_STOR_XFER_LONG)
+ fake_sense = 1;
+ }
+
+ /* get CSW for device status */
+ /* pr_info("Attempting to get CSW...\n"); */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen);
+
+ if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
+ /* pr_info("Received 0-length CSW; retrying...\n"); */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, &cswlen);
+ }
+
+ /* did the attempt to read the CSW fail? */
+ if (result == USB_STOR_XFER_STALLED) {
+ /* get the status again */
+ /* pr_info("Attempting to get CSW (2nd try)...\n"); */
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
+ US_BULK_CS_WRAP_LEN, NULL);
+ }
+
+ /* if we still have a failure at this point, we're in trouble */
+ /* pr_info("Bulk status result = %d\n", result); */
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ /* check bulk status */
+ residue = le32_to_cpu(bcs->Residue);
+ /* pr_info("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n",
+ le32_to_cpu(bcs->Signature),
+ bcs->Tag, residue, bcs->Status); */
+ if (!(bcs->Tag == us->tag ||
+ (us->fflags & US_FL_BULK_IGNORE_TAG)) ||
+ bcs->Status > US_BULK_STAT_PHASE) {
+ /* pr_info("Bulk logical error\n"); */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (!us->bcs_signature) {
+ us->bcs_signature = bcs->Signature;
+ /* if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN)) */
+ /* pr_info("Learnt BCS signature 0x%08X\n",
+ le32_to_cpu(us->bcs_signature)); */
+ } else if (bcs->Signature != us->bcs_signature) {
+ /* pr_info("Signature mismatch: got %08X, expecting %08X\n",
+ le32_to_cpu(bcs->Signature),
+ le32_to_cpu(us->bcs_signature)); */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ /* try to compute the actual residue, based on how much data
+ * was really transferred and what the device tells us */
+ if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
+
+ /* Heuristically detect devices that generate bogus residues
+ * by seeing what happens with INQUIRY and READ CAPACITY
+ * commands.
+ */
+ if (bcs->Status == US_BULK_STAT_OK &&
+ scsi_get_resid(srb) == 0 &&
+ ((srb->cmnd[0] == INQUIRY &&
+ transfer_length == 36) ||
+ (srb->cmnd[0] == READ_CAPACITY &&
+ transfer_length == 8))) {
+ us->fflags |= US_FL_IGNORE_RESIDUE;
+
+ } else {
+ residue = min(residue, transfer_length);
+ scsi_set_resid(srb, max_t(int, scsi_get_resid(srb),
+ residue));
+ }
+ }
+
+ /* based on the status code, we report good or bad */
+ switch (bcs->Status) {
+ case US_BULK_STAT_OK:
+ if (fake_sense) {
+ memcpy(srb->sense_buffer, usb_stor_sense_invalidCDB,
+ sizeof(usb_stor_sense_invalidCDB));
+ return USB_STOR_TRANSPORT_NO_SENSE;
+ }
+ return USB_STOR_TRANSPORT_GOOD;
+
+ case US_BULK_STAT_FAIL:
+ return USB_STOR_TRANSPORT_FAILED;
+
+ case US_BULK_STAT_PHASE:
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ return USB_STOR_TRANSPORT_ERROR;
+}
+
+/***********************************************************************
+ * Reset routines
+ ***********************************************************************/
+/*
+ * usb_stor_reset_common()
+ */
+static int usb_stor_reset_common(struct us_data *us,
+ u8 request, u8 requesttype,
+ u16 value, u16 index, void *data, u16 size)
+{
+ int result;
+ int result2;
+
+ /* pr_info("transport --- usb_stor_reset_common\n"); */
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ /* pr_info("No reset during disconnect\n"); */
+ return -EIO;
+ }
+
+ result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+ request, requesttype, value, index, data, size, 5*HZ);
+
+ if (result < 0) {
+ /* pr_info("Soft reset failed: %d\n", result); */
+ return result;
+ }
+
+ wait_event_interruptible_timeout(us->delay_wait,
+ test_bit(US_FLIDX_DISCONNECTING, &us->dflags), HZ*6);
+
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ /* pr_info("Reset interrupted by disconnect\n"); */
+ return -EIO;
+ }
+
+ /* pr_info("Soft reset: clearing bulk-in endpoint halt\n"); */
+ result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
+
+ /* pr_info("Soft reset: clearing bulk-out endpoint halt\n"); */
+ result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
+
+ /* return a result code based on the result of the clear-halts */
+ if (result >= 0)
+ result = result2;
+ /* if (result < 0) */
+ /* pr_info("Soft reset failed\n"); */
+ /* else */
+ /* pr_info("Soft reset done\n"); */
+ return result;
+}
+
+/*
+ * usb_stor_Bulk_reset()
+ */
+int usb_stor_Bulk_reset(struct us_data *us)
+{
+ /* pr_info("transport --- usb_stor_Bulk_reset\n"); */
+ return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 0, us->ifnum, NULL, 0);
+}
+
+/*
+ * usb_stor_port_reset()
+ */
+int usb_stor_port_reset(struct us_data *us)
+{
+ int result;
+
+ /* pr_info("transport --- usb_stor_port_reset\n"); */
+ result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+ if (result < 0)
+ pr_info("unable to lock device for reset: %d\n", result);
+ else {
+ /* Were we disconnected while waiting for the lock? */
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ result = -EIO;
+ /* pr_info("No reset during disconnect\n"); */
+ } else {
+ result = usb_reset_device(us->pusb_dev);
+ /* pr_info("usb_reset_composite_device returns %d\n",
+ result); */
+ }
+ usb_unlock_device(us->pusb_dev);
+ }
+ return result;
+}
+
+
diff --git a/drivers/staging/keucr/transport.h b/drivers/staging/keucr/transport.h
new file mode 100644
index 00000000000..abd8e5a3dd6
--- /dev/null
+++ b/drivers/staging/keucr/transport.h
@@ -0,0 +1,73 @@
+#ifndef _TRANSPORT_H_
+#define _TRANSPORT_H_
+
+#include <linux/blkdev.h>
+
+/* usb_stor_bulk_transfer_xxx() return codes, in order of severity */
+#define USB_STOR_XFER_GOOD 0 /* good transfer */
+#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */
+#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
+#define USB_STOR_XFER_LONG 3 /* device tried to send too much */
+#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */
+
+/* Transport return codes */
+#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
+#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
+#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */
+#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */
+
+/*
+ * We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
+ * return codes. But now the transport and low-level transfer routines
+ * treat an abort as just another error (-ENOENT for a cancelled URB).
+ * It is up to the invoke_transport() function to test for aborts and
+ * distinguish them from genuine communication errors.
+ */
+
+/* CBI accept device specific command */
+#define US_CBI_ADSC 0
+extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*);
+extern int usb_stor_Bulk_max_lun(struct us_data *);
+extern int usb_stor_Bulk_reset(struct us_data *);
+extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*);
+extern void usb_stor_stop_transport(struct us_data *);
+extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size, int timeout);
+extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe);
+extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+ void *buf, unsigned int length, unsigned int *act_len);
+extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
+ void *buf, unsigned int length, int use_sg, int *residual);
+extern int usb_stor_bulk_srb(struct us_data *us, unsigned int pipe,
+ struct scsi_cmnd *srb);
+extern int usb_stor_port_reset(struct us_data *us);
+
+/* Protocol handling routines */
+enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF};
+extern unsigned int usb_stor_access_xfer_buf(struct us_data*,
+ unsigned char *buffer, unsigned int buflen, struct scsi_cmnd *srb,
+ struct scatterlist **, unsigned int *offset, enum xfer_buf_dir dir);
+extern void usb_stor_set_xfer_buf(struct us_data*, unsigned char *buffer,
+ unsigned int buflen, struct scsi_cmnd *srb,
+ unsigned int dir);
+
+/*
+ * ENE scsi function
+ */
+extern void ENE_stor_invoke_transport(struct scsi_cmnd *, struct us_data *);
+extern int ENE_InitMedia(struct us_data *);
+extern int ENE_SMInit(struct us_data *);
+extern int ENE_SendScsiCmd(struct us_data*, u8, void*, int);
+extern int ENE_LoadBinCode(struct us_data*, u8);
+extern int ene_read_byte(struct us_data*, u16 index, void *buf);
+extern int ENE_Read_Data(struct us_data*, void *buf, unsigned int length);
+extern int ENE_Write_Data(struct us_data*, void *buf, unsigned int length);
+extern void BuildSenseBuffer(struct scsi_cmnd *, int);
+
+/*
+ * ENE scsi function
+ */
+extern int SM_SCSIIrp(struct us_data *us, struct scsi_cmnd *srb);
+
+#endif
diff --git a/drivers/staging/keucr/usb.c b/drivers/staging/keucr/usb.c
new file mode 100644
index 00000000000..12ebde7315c
--- /dev/null
+++ b/drivers/staging/keucr/usb.c
@@ -0,0 +1,642 @@
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/freezer.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/utsname.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "scsiglue.h"
+#include "smil.h"
+#include "transport.h"
+
+/* Some informational data */
+MODULE_AUTHOR("Domao");
+MODULE_DESCRIPTION("ENE USB Mass Storage driver for Linux");
+MODULE_LICENSE("GPL");
+
+static unsigned int delay_use = 1;
+
+static struct usb_device_id eucr_usb_ids[] = {
+ { USB_DEVICE(0x058f, 0x6366) },
+ { USB_DEVICE(0x0cf2, 0x6230) },
+ { USB_DEVICE(0x0cf2, 0x6250) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, eucr_usb_ids);
+
+
+#ifdef CONFIG_PM
+
+static int eucr_suspend(struct usb_interface *iface, pm_message_t message)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+ pr_info("--- eucr_suspend ---\n");
+ /* Wait until no command is running */
+ mutex_lock(&us->dev_mutex);
+
+ if (us->suspend_resume_hook)
+ (us->suspend_resume_hook)(us, US_SUSPEND);
+
+ mutex_unlock(&us->dev_mutex);
+ return 0;
+}
+
+static int eucr_resume(struct usb_interface *iface)
+{
+ u8 tmp = 0;
+
+ struct us_data *us = usb_get_intfdata(iface);
+ pr_info("--- eucr_resume---\n");
+ mutex_lock(&us->dev_mutex);
+
+ if (us->suspend_resume_hook)
+ (us->suspend_resume_hook)(us, US_RESUME);
+
+
+ mutex_unlock(&us->dev_mutex);
+
+ us->Power_IsResum = true;
+
+ us->SM_Status = *(struct keucr_sm_status *)&tmp;
+
+ return 0;
+}
+
+static int eucr_reset_resume(struct usb_interface *iface)
+{
+ u8 tmp = 0;
+ struct us_data *us = usb_get_intfdata(iface);
+
+ pr_info("--- eucr_reset_resume---\n");
+
+ /* Report the reset to the SCSI core */
+ usb_stor_report_bus_reset(us);
+
+ /*
+ * FIXME: Notify the subdrivers that they need to reinitialize
+ * the device
+ */
+
+ us->Power_IsResum = true;
+
+ us->SM_Status = *(struct keucr_sm_status *)&tmp;
+
+ return 0;
+}
+
+#else
+
+#define eucr_suspend NULL
+#define eucr_resume NULL
+#define eucr_reset_resume NULL
+
+#endif
+
+static int eucr_pre_reset(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ pr_info("usb --- eucr_pre_reset\n");
+
+ /* Make sure no command runs during the reset */
+ mutex_lock(&us->dev_mutex);
+ return 0;
+}
+
+static int eucr_post_reset(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ pr_info("usb --- eucr_post_reset\n");
+
+ /* Report the reset to the SCSI core */
+ usb_stor_report_bus_reset(us);
+
+ mutex_unlock(&us->dev_mutex);
+ return 0;
+}
+
+void fill_inquiry_response(struct us_data *us, unsigned char *data,
+ unsigned int data_len)
+{
+ pr_info("usb --- fill_inquiry_response\n");
+ if (data_len < 36) /* You lose. */
+ return;
+
+ if (data[0]&0x20) {
+ memset(data+8, 0, 28);
+ } else {
+ u16 bcdDevice =
+ le16_to_cpu(us->pusb_dev->descriptor.bcdDevice);
+ memcpy(data+8, us->unusual_dev->vendorName,
+ strlen(us->unusual_dev->vendorName) > 8 ? 8 :
+ strlen(us->unusual_dev->vendorName));
+ memcpy(data+16, us->unusual_dev->productName,
+ strlen(us->unusual_dev->productName) > 16 ? 16 :
+ strlen(us->unusual_dev->productName));
+ data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);
+ data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
+ data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
+ data[35] = 0x30 + ((bcdDevice) & 0x0F);
+ }
+ usb_stor_set_xfer_buf(us, data, data_len, us->srb, TO_XFER_BUF);
+}
+
+static int usb_stor_control_thread(void *__us)
+{
+ struct us_data *us = (struct us_data *)__us;
+ struct Scsi_Host *host = us_to_host(us);
+
+ pr_info("usb --- usb_stor_control_thread\n");
+ for (;;) {
+ if (wait_for_completion_interruptible(&us->cmnd_ready))
+ break;
+
+ /* lock the device pointers */
+ mutex_lock(&(us->dev_mutex));
+
+ /* if the device has disconnected, we are free to exit */
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
+ mutex_unlock(&us->dev_mutex);
+ break;
+ }
+
+ /* lock access to the state */
+ scsi_lock(host);
+
+ /* When we are called with no command pending, we're done */
+ if (us->srb == NULL) {
+ scsi_unlock(host);
+ mutex_unlock(&us->dev_mutex);
+ break;
+ }
+
+ /* has the command timed out *already* ? */
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ us->srb->result = DID_ABORT << 16;
+ goto SkipForAbort;
+ }
+
+ scsi_unlock(host);
+
+ if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
+ us->srb->result = DID_ERROR << 16;
+ } else if (us->srb->device->id
+ && !(us->fflags & US_FL_SCM_MULT_TARG)) {
+ us->srb->result = DID_BAD_TARGET << 16;
+ } else if (us->srb->device->lun > us->max_lun) {
+ us->srb->result = DID_BAD_TARGET << 16;
+ } else if ((us->srb->cmnd[0] == INQUIRY)
+ && (us->fflags & US_FL_FIX_INQUIRY)) {
+ unsigned char data_ptr[36] = {0x00, 0x80, 0x02, 0x02,
+ 0x1F, 0x00, 0x00, 0x00};
+
+ fill_inquiry_response(us, data_ptr, 36);
+ us->srb->result = SAM_STAT_GOOD;
+ } else {
+ us->proto_handler(us->srb, us);
+ }
+
+ /* lock access to the state */
+ scsi_lock(host);
+
+ /* indicate that the command is done */
+ if (us->srb->result != DID_ABORT << 16) {
+ us->srb->scsi_done(us->srb);
+ } else {
+SkipForAbort:
+ pr_info("scsi command aborted\n");
+ }
+
+ if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
+ complete(&(us->notify));
+
+ /* Allow USB transfers to resume */
+ clear_bit(US_FLIDX_ABORTING, &us->dflags);
+ clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
+ }
+
+ /* finished working on this command */
+ us->srb = NULL;
+ scsi_unlock(host);
+
+ /* unlock the device pointers */
+ mutex_unlock(&us->dev_mutex);
+ } /* for (;;) */
+
+ /* Wait until we are told to stop */
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (kthread_should_stop())
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+ return 0;
+}
+
+static int associate_dev(struct us_data *us, struct usb_interface *intf)
+{
+ pr_info("usb --- associate_dev\n");
+
+ /* Fill in the device-related fields */
+ us->pusb_dev = interface_to_usbdev(intf);
+ us->pusb_intf = intf;
+ us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+
+ /* Store our private data in the interface */
+ usb_set_intfdata(intf, us);
+
+ /* Allocate the device-related DMA-mapped buffers */
+ us->cr = usb_alloc_coherent(us->pusb_dev, sizeof(*us->cr), GFP_KERNEL,
+ &us->cr_dma);
+ if (!us->cr) {
+ pr_info("usb_ctrlrequest allocation failed\n");
+ return -ENOMEM;
+ }
+
+ us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE, GFP_KERNEL,
+ &us->iobuf_dma);
+ if (!us->iobuf) {
+ pr_info("I/O buffer allocation failed\n");
+ return -ENOMEM;
+ }
+
+ us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL);
+ if (!us->sensebuf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int get_device_info(struct us_data *us, const struct usb_device_id *id)
+{
+ struct usb_device *dev = us->pusb_dev;
+ struct usb_interface_descriptor *idesc =
+ &us->pusb_intf->cur_altsetting->desc;
+
+ pr_info("usb --- get_device_info\n");
+
+ us->subclass = idesc->bInterfaceSubClass;
+ us->protocol = idesc->bInterfaceProtocol;
+ us->fflags = id->driver_info;
+ us->Power_IsResum = false;
+
+ if (us->fflags & US_FL_IGNORE_DEVICE) {
+ pr_info("device ignored\n");
+ return -ENODEV;
+ }
+
+ if (dev->speed != USB_SPEED_HIGH)
+ us->fflags &= ~US_FL_GO_SLOW;
+
+ return 0;
+}
+
+static int get_transport(struct us_data *us)
+{
+ pr_info("usb --- get_transport\n");
+ switch (us->protocol) {
+ case USB_PR_BULK:
+ us->transport_name = "Bulk";
+ us->transport = usb_stor_Bulk_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ /* fix for single-lun devices */
+ if (us->fflags & US_FL_SINGLE_LUN)
+ us->max_lun = 0;
+ return 0;
+}
+
+static int get_protocol(struct us_data *us)
+{
+ pr_info("usb --- get_protocol\n");
+ pr_info("us->pusb_dev->descriptor.idVendor = %x\n",
+ us->pusb_dev->descriptor.idVendor);
+ pr_info("us->pusb_dev->descriptor.idProduct = %x\n",
+ us->pusb_dev->descriptor.idProduct);
+ switch (us->subclass) {
+ case USB_SC_SCSI:
+ us->protocol_name = "Transparent SCSI";
+ if ((us->pusb_dev->descriptor.idVendor == 0x0CF2)
+ && (us->pusb_dev->descriptor.idProduct == 0x6250))
+ us->proto_handler = ENE_stor_invoke_transport;
+ else
+ us->proto_handler = usb_stor_invoke_transport;
+ break;
+
+ default:
+ return -EIO;
+ }
+ return 0;
+}
+
+static int get_pipes(struct us_data *us)
+{
+ struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting;
+ int i;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_endpoint_descriptor *ep_in = NULL;
+ struct usb_endpoint_descriptor *ep_out = NULL;
+ struct usb_endpoint_descriptor *ep_int = NULL;
+
+ pr_info("usb --- get_pipes\n");
+
+ for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
+ ep = &altsetting->endpoint[i].desc;
+
+ if (usb_endpoint_xfer_bulk(ep)) {
+ if (usb_endpoint_dir_in(ep)) {
+ if (!ep_in)
+ ep_in = ep;
+ } else {
+ if (!ep_out)
+ ep_out = ep;
+ }
+ } else if (usb_endpoint_is_int_in(ep)) {
+ if (!ep_int)
+ ep_int = ep;
+ }
+ }
+
+ if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) {
+ pr_info("Endpoint sanity check failed! Rejecting dev.\n");
+ return -EIO;
+ }
+
+ /* Calculate and store the pipe values */
+ us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
+ us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
+ us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
+ ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
+ ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ if (ep_int) {
+ us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
+ ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ us->ep_bInterval = ep_int->bInterval;
+ }
+ return 0;
+}
+
+static int usb_stor_acquire_resources(struct us_data *us)
+{
+ struct task_struct *th;
+
+ pr_info("usb --- usb_stor_acquire_resources\n");
+ us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!us->current_urb) {
+ pr_info("URB allocation failed\n");
+ return -ENOMEM;
+ }
+
+ /* Start up our control thread */
+ th = kthread_run(usb_stor_control_thread, us, "eucr-storage");
+ if (IS_ERR(th)) {
+ pr_info("Unable to start control thread\n");
+ return PTR_ERR(th);
+ }
+ us->ctl_thread = th;
+
+ return 0;
+}
+
+static void usb_stor_release_resources(struct us_data *us)
+{
+ pr_info("usb --- usb_stor_release_resources\n");
+
+ SM_FreeMem();
+
+ complete(&us->cmnd_ready);
+ if (us->ctl_thread)
+ kthread_stop(us->ctl_thread);
+
+ /* Call the destructor routine, if it exists */
+ if (us->extra_destructor) {
+ pr_info("-- calling extra_destructor()\n");
+ us->extra_destructor(us->extra);
+ }
+
+ /* Free the extra data and the URB */
+ kfree(us->extra);
+ usb_free_urb(us->current_urb);
+}
+
+static void dissociate_dev(struct us_data *us)
+{
+ pr_info("usb --- dissociate_dev\n");
+
+ kfree(us->sensebuf);
+
+ /* Free the device-related DMA-mapped buffers */
+ usb_free_coherent(us->pusb_dev, sizeof(*us->cr), us->cr, us->cr_dma);
+ usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf,
+ us->iobuf_dma);
+
+ /* Remove our private data from the interface */
+ usb_set_intfdata(us->pusb_intf, NULL);
+}
+
+static void quiesce_and_remove_host(struct us_data *us)
+{
+ struct Scsi_Host *host = us_to_host(us);
+
+ pr_info("usb --- quiesce_and_remove_host\n");
+
+ /* If the device is really gone, cut short reset delays */
+ if (us->pusb_dev->state == USB_STATE_NOTATTACHED)
+ set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
+
+ /*
+ * Prevent SCSI-scanning (if it hasn't started yet)
+ * and wait for the SCSI-scanning thread to stop.
+ */
+ set_bit(US_FLIDX_DONT_SCAN, &us->dflags);
+ wake_up(&us->delay_wait);
+ wait_for_completion(&us->scanning_done);
+
+ /*
+ * Removing the host will perform an orderly shutdown: caches
+ * synchronized, disks spun down, etc.
+ */
+ scsi_remove_host(host);
+
+ /*
+ * Prevent any new commands from being accepted and cut short
+ * reset delays.
+ */
+ scsi_lock(host);
+ set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
+ scsi_unlock(host);
+ wake_up(&us->delay_wait);
+}
+
+static void release_everything(struct us_data *us)
+{
+ pr_info("usb --- release_everything\n");
+
+ usb_stor_release_resources(us);
+ dissociate_dev(us);
+ scsi_host_put(us_to_host(us));
+}
+
+static int usb_stor_scan_thread(void *__us)
+{
+ struct us_data *us = (struct us_data *)__us;
+
+ pr_info("usb --- usb_stor_scan_thread\n");
+ pr_info("EUCR : device found at %d\n", us->pusb_dev->devnum);
+
+ set_freezable();
+ /* Wait for the timeout to expire or for a disconnect */
+ if (delay_use > 0) {
+ wait_event_freezable_timeout(us->delay_wait,
+ test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
+ delay_use * HZ);
+ }
+
+ /* If the device is still connected, perform the scanning */
+ if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) {
+ /* For bulk-only devices, determine the max LUN value */
+ if (us->protocol == USB_PR_BULK
+ && !(us->fflags & US_FL_SINGLE_LUN)) {
+ mutex_lock(&us->dev_mutex);
+ us->max_lun = usb_stor_Bulk_max_lun(us);
+ mutex_unlock(&us->dev_mutex);
+ }
+ scsi_scan_host(us_to_host(us));
+ pr_info("EUCR : device scan complete\n");
+ }
+ complete_and_exit(&us->scanning_done, 0);
+}
+
+static int eucr_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct Scsi_Host *host;
+ struct us_data *us;
+ int result;
+ u8 MiscReg03 = 0;
+ struct task_struct *th;
+
+ pr_info("usb --- eucr_probe\n");
+
+ host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));
+ if (!host) {
+ pr_info("Unable to allocate the scsi host\n");
+ return -ENOMEM;
+ }
+
+ /* Allow 16-byte CDBs and thus > 2TB */
+ host->max_cmd_len = 16;
+ us = host_to_us(host);
+ memset(us, 0, sizeof(struct us_data));
+ mutex_init(&(us->dev_mutex));
+ init_completion(&us->cmnd_ready);
+ init_completion(&(us->notify));
+ init_waitqueue_head(&us->delay_wait);
+ init_completion(&us->scanning_done);
+
+ /* Associate the us_data structure with the USB device */
+ result = associate_dev(us, intf);
+ if (result)
+ goto BadDevice;
+
+ /* Get Device info */
+ result = get_device_info(us, id);
+ if (result)
+ goto BadDevice;
+
+ /* Get the transport, protocol, and pipe settings */
+ result = get_transport(us);
+ if (result)
+ goto BadDevice;
+ result = get_protocol(us);
+ if (result)
+ goto BadDevice;
+ result = get_pipes(us);
+ if (result)
+ goto BadDevice;
+
+ /* Acquire all the other resources and add the host */
+ result = usb_stor_acquire_resources(us);
+ if (result)
+ goto BadDevice;
+
+ result = scsi_add_host(host, &intf->dev);
+ if (result) {
+ pr_info("Unable to add the scsi host\n");
+ goto BadDevice;
+ }
+
+ /* Start up the thread for delayed SCSI-device scanning */
+ th = kthread_create(usb_stor_scan_thread, us, "eucr-stor-scan");
+ if (IS_ERR(th)) {
+ pr_info("Unable to start the device-scanning thread\n");
+ complete(&us->scanning_done);
+ quiesce_and_remove_host(us);
+ result = PTR_ERR(th);
+ goto BadDevice;
+ }
+ wake_up_process(th);
+
+ /* probe card type */
+ result = ene_read_byte(us, REG_CARD_STATUS, &MiscReg03);
+ if (result != USB_STOR_XFER_GOOD) {
+ result = USB_STOR_TRANSPORT_ERROR;
+ quiesce_and_remove_host(us);
+ goto BadDevice;
+ }
+
+ if (!(MiscReg03 & 0x02)) {
+ result = -ENODEV;
+ quiesce_and_remove_host(us);
+ pr_info("keucr: The driver only supports SM/MS card. To use SD card, please build driver/usb/storage/ums-eneub6250.ko\n");
+ goto BadDevice;
+ }
+
+ return 0;
+
+ /* We come here if there are any problems */
+BadDevice:
+ pr_info("usb --- eucr_probe failed\n");
+ release_everything(us);
+ return result;
+}
+
+static void eucr_disconnect(struct usb_interface *intf)
+{
+ struct us_data *us = usb_get_intfdata(intf);
+
+ pr_info("usb --- eucr_disconnect\n");
+ quiesce_and_remove_host(us);
+ release_everything(us);
+}
+
+/* Initialization and registration */
+static struct usb_driver usb_storage_driver = {
+ .name = "eucr",
+ .probe = eucr_probe,
+ .suspend = eucr_suspend,
+ .resume = eucr_resume,
+ .reset_resume = eucr_reset_resume,
+ .disconnect = eucr_disconnect,
+ .pre_reset = eucr_pre_reset,
+ .post_reset = eucr_post_reset,
+ .id_table = eucr_usb_ids,
+ .soft_unbind = 1,
+};
+
+module_usb_driver(usb_storage_driver);
diff --git a/drivers/staging/keucr/usb.h b/drivers/staging/keucr/usb.h
new file mode 100644
index 00000000000..e894f840c70
--- /dev/null
+++ b/drivers/staging/keucr/usb.h
@@ -0,0 +1,240 @@
+/* Driver for USB Mass Storage compliant devices */
+
+#ifndef _USB_H_
+#define _USB_H_
+
+#include <linux/usb.h>
+#include <linux/usb_usual.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <scsi/scsi_host.h>
+#include "common.h"
+
+struct us_data;
+struct scsi_cmnd;
+
+/*
+ * Unusual device list definitions
+ */
+
+struct us_unusual_dev {
+ const char *vendorName;
+ const char *productName;
+ __u8 useProtocol;
+ __u8 useTransport;
+ int (*initFunction)(struct us_data *);
+};
+
+/* EnE HW Register */
+#define REG_CARD_STATUS 0xFF83
+#define REG_HW_TRAP1 0xFF89
+
+/* SRB Status. Refers /usr/include/wine/wine/wnaspi32.h & SCSI sense key */
+#define SS_SUCCESS 0x00 /* No Sense */
+#define SS_NOT_READY 0x02
+#define SS_MEDIUM_ERR 0x03
+#define SS_HW_ERR 0x04
+#define SS_ILLEGAL_REQUEST 0x05
+#define SS_UNIT_ATTENTION 0x06
+
+/* ENE Load FW Pattern */
+#define SD_INIT1_PATTERN 1
+#define SD_INIT2_PATTERN 2
+#define SD_RW_PATTERN 3
+#define MS_INIT_PATTERN 4
+#define MSP_RW_PATTERN 5
+#define MS_RW_PATTERN 6
+#define SM_INIT_PATTERN 7
+#define SM_RW_PATTERN 8
+
+#define FDIR_WRITE 0
+#define FDIR_READ 1
+
+struct keucr_sd_status {
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 IsMMC:1;
+ u8 HiCapacity:1;
+ u8 HiSpeed:1;
+ u8 WtP:1;
+ u8 Reserved:1;
+};
+
+struct keucr_ms_status {
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 IsMSPro:1;
+ u8 IsMSPHG:1;
+ u8 Reserved1:1;
+ u8 WtP:1;
+ u8 Reserved2:1;
+};
+
+struct keucr_sm_status {
+ u8 Insert:1;
+ u8 Ready:1;
+ u8 MediaChange:1;
+ u8 Reserved:3;
+ u8 WtP:1;
+ u8 IsMS:1;
+};
+
+/* SD Block Length */
+#define SD_BLOCK_LEN 9 /* 2^9 = 512 Bytes,
+ The HW maximum read/write data length */
+
+/* Dynamic bitflag definitions (us->dflags): used in set_bit() etc. */
+#define US_FLIDX_URB_ACTIVE 0 /* current_urb is in use */
+#define US_FLIDX_SG_ACTIVE 1 /* current_sg is in use */
+#define US_FLIDX_ABORTING 2 /* abort is in progress */
+#define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */
+#define US_FLIDX_RESETTING 4 /* device reset in progress */
+#define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */
+#define US_FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */
+
+
+#define USB_STOR_STRING_LEN 32
+
+/*
+ * We provide a DMA-mapped I/O buffer for use with small USB transfers.
+ * It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a
+ * 31-byte buffer. But Freecom needs a 64-byte buffer, so that's the
+ * size we'll allocate.
+ */
+
+#define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */
+#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */
+
+typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data *);
+typedef int (*trans_reset)(struct us_data *);
+typedef void (*proto_cmnd)(struct scsi_cmnd *, struct us_data *);
+typedef void (*extra_data_destructor)(void *); /* extra data destructor */
+typedef void (*pm_hook)(struct us_data *, int); /* power management hook */
+
+#define US_SUSPEND 0
+#define US_RESUME 1
+
+/* we allocate one of these for every device that we remember */
+struct us_data {
+ /* The device we're working with
+ * It's important to note:
+ * (o) you must hold dev_mutex to change pusb_dev
+ */
+ struct mutex dev_mutex; /* protect pusb_dev */
+ struct usb_device *pusb_dev; /* this usb_device */
+ struct usb_interface *pusb_intf; /* this interface */
+ struct us_unusual_dev *unusual_dev; /* device-filter entry */
+ unsigned long fflags; /* fixed flags from filter */
+ unsigned long dflags; /* dynamic atomic bitflags */
+ unsigned int send_bulk_pipe; /* cached pipe values */
+ unsigned int recv_bulk_pipe;
+ unsigned int send_ctrl_pipe;
+ unsigned int recv_ctrl_pipe;
+ unsigned int recv_intr_pipe;
+
+ /* information about the device */
+ char *transport_name;
+ char *protocol_name;
+ __le32 bcs_signature;
+ u8 subclass;
+ u8 protocol;
+ u8 max_lun;
+
+ u8 ifnum; /* interface number */
+ u8 ep_bInterval; /* interrupt interval */
+
+ /* function pointers for this device */
+ trans_cmnd transport; /* transport function */
+ trans_reset transport_reset; /* transport device reset */
+ proto_cmnd proto_handler; /* protocol handler */
+
+ /* SCSI interfaces */
+ struct scsi_cmnd *srb; /* current srb */
+ unsigned int tag; /* current dCBWTag */
+
+ /* control and bulk communications data */
+ struct urb *current_urb; /* USB requests */
+ struct usb_ctrlrequest *cr; /* control requests */
+ struct usb_sg_request current_sg; /* scatter-gather req. */
+ unsigned char *iobuf; /* I/O buffer */
+ unsigned char *sensebuf; /* sense data buffer */
+ dma_addr_t cr_dma; /* buffer DMA addresses */
+ dma_addr_t iobuf_dma;
+ struct task_struct *ctl_thread; /* the control thread */
+
+ /* mutual exclusion and synchronization structures */
+ struct completion cmnd_ready; /* to sleep thread on */
+ struct completion notify; /* thread begin/end */
+ wait_queue_head_t delay_wait; /* wait during scan, reset */
+ struct completion scanning_done; /* wait for scan thread */
+
+ /* subdriver information */
+ void *extra; /* Any extra data */
+ extra_data_destructor extra_destructor;/* extra data destructor */
+#ifdef CONFIG_PM
+ pm_hook suspend_resume_hook;
+#endif
+ /* for 6250 code */
+ struct keucr_sd_status SD_Status;
+ struct keucr_ms_status MS_Status;
+ struct keucr_sm_status SM_Status;
+
+ /* ----- SD Control Data ---------------- */
+ /* SD_REGISTER SD_Regs; */
+ u16 SD_Block_Mult;
+ u8 SD_READ_BL_LEN;
+ u16 SD_C_SIZE;
+ u8 SD_C_SIZE_MULT;
+
+ /* SD/MMC New spec. */
+ u8 SD_SPEC_VER;
+ u8 SD_CSD_VER;
+ u8 SD20_HIGH_CAPACITY;
+ u32 HC_C_SIZE;
+ u8 MMC_SPEC_VER;
+ u8 MMC_BusWidth;
+ u8 MMC_HIGH_CAPACITY;
+
+ /* ----- MS Control Data ---------------- */
+ bool MS_SWWP;
+ u32 MSP_TotalBlock;
+ /* MS_LibControl MS_Lib; */
+ bool MS_IsRWPage;
+ u16 MS_Model;
+
+ /* ----- SM Control Data ---------------- */
+ u8 SM_DeviceID;
+ u8 SM_CardID;
+
+ u8 *testbuf;
+ u8 BIN_FLAG;
+ u32 bl_num;
+ int SrbStatus;
+
+ /* ------Power Managerment --------------- */
+ bool Power_IsResum;
+};
+
+/* Convert between us_data and the corresponding Scsi_Host */
+static inline struct Scsi_Host *us_to_host(struct us_data *us)
+{
+ return container_of((void *) us, struct Scsi_Host, hostdata);
+}
+static inline struct us_data *host_to_us(struct Scsi_Host *host)
+{
+ return (struct us_data *) host->hostdata;
+}
+
+/* Function to fill an inquiry response. See usb.c for details */
+extern void fill_inquiry_response(struct us_data *us,
+ unsigned char *data, unsigned int data_len);
+
+/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the
+ * single queue element srb for write access */
+#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
+#define scsi_lock(host) spin_lock_irq(host->host_lock)
+
+#endif