diff options
Diffstat (limited to 'drivers/staging/keucr')
| -rw-r--r-- | drivers/staging/keucr/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/staging/keucr/Makefile | 13 | ||||
| -rw-r--r-- | drivers/staging/keucr/TODO | 12 | ||||
| -rw-r--r-- | drivers/staging/keucr/common.h | 7 | ||||
| -rw-r--r-- | drivers/staging/keucr/init.c | 333 | ||||
| -rw-r--r-- | drivers/staging/keucr/init.h | 518 | ||||
| -rw-r--r-- | drivers/staging/keucr/scsiglue.c | 467 | ||||
| -rw-r--r-- | drivers/staging/keucr/scsiglue.h | 10 | ||||
| -rw-r--r-- | drivers/staging/keucr/smcommon.h | 29 | ||||
| -rw-r--r-- | drivers/staging/keucr/smil.h | 288 | ||||
| -rw-r--r-- | drivers/staging/keucr/smilecc.c | 211 | ||||
| -rw-r--r-- | drivers/staging/keucr/smilmain.c | 760 | ||||
| -rw-r--r-- | drivers/staging/keucr/smilsub.c | 679 | ||||
| -rw-r--r-- | drivers/staging/keucr/smscsi.c | 194 | ||||
| -rw-r--r-- | drivers/staging/keucr/transport.c | 865 | ||||
| -rw-r--r-- | drivers/staging/keucr/transport.h | 73 | ||||
| -rw-r--r-- | drivers/staging/keucr/usb.c | 642 | ||||
| -rw-r--r-- | drivers/staging/keucr/usb.h | 240 |
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 |
