diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/staging/keucr | |
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 | 15 | ||||
| -rw-r--r-- | drivers/staging/keucr/init.c | 372 | ||||
| -rw-r--r-- | drivers/staging/keucr/init.h | 523 | ||||
| -rw-r--r-- | drivers/staging/keucr/scsiglue.c | 469 | ||||
| -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 | 311 | ||||
| -rw-r--r-- | drivers/staging/keucr/smilecc.c | 211 | ||||
| -rw-r--r-- | drivers/staging/keucr/smilmain.c | 1850 | ||||
| -rw-r--r-- | drivers/staging/keucr/smilsub.c | 693 | ||||
| -rw-r--r-- | drivers/staging/keucr/smscsi.c | 188 | ||||
| -rw-r--r-- | drivers/staging/keucr/transport.c | 823 | ||||
| -rw-r--r-- | drivers/staging/keucr/transport.h | 74 | ||||
| -rw-r--r-- | drivers/staging/keucr/usb.c | 636 | ||||
| -rw-r--r-- | drivers/staging/keucr/usb.h | 237 |
18 files changed, 6480 insertions, 0 deletions
diff --git a/drivers/staging/keucr/Kconfig b/drivers/staging/keucr/Kconfig new file mode 100644 index 00000000..ba756bf2 --- /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 00000000..c180bf4f --- /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 00000000..d6da656e --- /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 00000000..cf347ccd --- /dev/null +++ b/drivers/staging/keucr/common.h @@ -0,0 +1,15 @@ +#ifndef COMMON_INCD +#define COMMON_INCD + +typedef u8 BOOLEAN; +typedef u8 BYTE; +typedef u8 *PBYTE; +typedef u16 WORD; +typedef u16 *PWORD; +typedef u32 DWORD; +typedef u32 *PDWORD; + +#define BYTE_MASK 0xff + +#endif + diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c new file mode 100644 index 00000000..231611dc --- /dev/null +++ b/drivers/staging/keucr/init.c @@ -0,0 +1,372 @@ +#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 "init.h" + +/* + * ENE_InitMedia(): + */ +int ENE_InitMedia(struct us_data *us) +{ + int result; + BYTE MiscReg03 = 0; + + printk(KERN_INFO "--- Init Media ---\n"); + result = ENE_Read_BYTE(us, REG_CARD_STATUS, &MiscReg03); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_ERR "Read register fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + printk(KERN_INFO "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, WORD 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] = (BYTE)(index>>8); + bcb->CDB[3] = (BYTE)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; + BYTE buf[0x200]; + + printk(KERN_INFO "transport --- ENE_SMInit\n"); + + result = ENE_LoadBinCode(us, SM_INIT_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk(KERN_INFO "Load SM Init Code Fail !!\n"); + 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) { + printk(KERN_ERR + "Execution SM Init Code Fail !! result = %x\n", result); + return USB_STOR_TRANSPORT_ERROR; + } + + us->SM_Status = *(PSM_STATUS)&buf[0]; + + us->SM_DeviceID = buf[1]; + us->SM_CardID = buf[2]; + + if (us->SM_Status.Insert && us->SM_Status.Ready) { + printk(KERN_INFO "Insert = %x\n", us->SM_Status.Insert); + printk(KERN_INFO "Ready = %x\n", us->SM_Status.Ready); + printk(KERN_INFO "WtP = %x\n", us->SM_Status.WtP); + printk(KERN_INFO "DeviceID = %x\n", us->SM_DeviceID); + printk(KERN_INFO "CardID = %x\n", us->SM_CardID); + MediaChange = 1; + Check_D_MediaFmt(us); + } else { + printk(KERN_ERR "SM 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, BYTE flag) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + /* void *buf; */ + PBYTE buf; + + /* printk(KERN_INFO "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: + printk(KERN_INFO "SM_INIT_PATTERN\n"); + memcpy(buf, SM_Init, 0x800); + break; + case SM_RW_PATTERN: + printk(KERN_INFO "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, BYTE 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; + + /* printk(KERN_INFO "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) { + printk(KERN_ERR "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) { + printk(KERN_ERR "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) { + printk(KERN_WARNING "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 */ + printk(KERN_WARNING "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; + + /* printk(KERN_INFO "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; +} + +/* + * usb_stor_print_cmd(): + */ +void usb_stor_print_cmd(struct scsi_cmnd *srb) +{ + PBYTE Cdb = srb->cmnd; + DWORD cmd = Cdb[0]; + DWORD bn = ((Cdb[2] << 24) & 0xff000000) | + ((Cdb[3] << 16) & 0x00ff0000) | + ((Cdb[4] << 8) & 0x0000ff00) | + ((Cdb[5] << 0) & 0x000000ff); + WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff); + + switch (cmd) { + case TEST_UNIT_READY: + /* printk(KERN_INFO + "scsi cmd %X --- SCSIOP_TEST_UNIT_READY\n", cmd); */ + break; + case INQUIRY: + printk(KERN_INFO "scsi cmd %X --- SCSIOP_INQUIRY\n", cmd); + break; + case MODE_SENSE: + printk(KERN_INFO "scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd); + break; + case START_STOP: + printk(KERN_INFO "scsi cmd %X --- SCSIOP_START_STOP\n", cmd); + break; + case READ_CAPACITY: + printk(KERN_INFO "scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd); + break; + case READ_10: + /* printk(KERN_INFO + "scsi cmd %X --- SCSIOP_READ,bn = %X, blen = %X\n" + ,cmd, bn, blen); */ + break; + case WRITE_10: + /* printk(KERN_INFO + "scsi cmd %X --- SCSIOP_WRITE, + bn = %X, blen = %X\n" , cmd, bn, blen); */ + break; + case ALLOW_MEDIUM_REMOVAL: + printk(KERN_INFO + "scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd); + break; + default: + printk(KERN_INFO "scsi cmd %X --- Other cmd\n", cmd); + break; + } + bn = 0; + blen = 0; +} + diff --git a/drivers/staging/keucr/init.h b/drivers/staging/keucr/init.h new file mode 100644 index 00000000..c8b2cd60 --- /dev/null +++ b/drivers/staging/keucr/init.h @@ -0,0 +1,523 @@ +#include "common.h" + +extern DWORD MediaChange; +extern int Check_D_MediaFmt(struct us_data *); + + + +static BYTE 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 BYTE 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 00000000..48e10053 --- /dev/null +++ b/drivers/staging/keucr/scsiglue.c @@ -0,0 +1,469 @@ +#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" + __FUNCTION__, 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)); + printk("-- 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 */ +/* + * show_max_sectors() + */ +static ssize_t show_max_sectors(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 */ +/* + * store_max_sectors() + */ +static ssize_t store_max_sectors(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(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors, store_max_sectors); +static struct device_attribute *sysfs_device_attr_list[] = {&dev_attr_max_sectors, NULL, }; + +/* this defines our host template, with which we'll allocate hosts */ + +/* + * 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 00000000..c7e59f0f --- /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 00000000..4d57203b --- /dev/null +++ b/drivers/staging/keucr/smcommon.h @@ -0,0 +1,29 @@ +/*----- < SMCommon.h> --------------------------------------------------*/ +#ifndef SMCOMMON_INCD +#define SMCOMMON_INCD + + +/*************************************************************************** +Define Difinetion +***************************************************************************/ +#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 00000000..24a636a4 --- /dev/null +++ b/drivers/staging/keucr/smil.h @@ -0,0 +1,311 @@ +/*----- < 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 difinition 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 SSFDCTYPE { + BYTE Model; + BYTE Attribute; + BYTE MaxZones; + BYTE MaxSectors; + WORD MaxBlocks; + WORD MaxLogBlocks; +}; + +typedef struct SSFDCTYPE_T { + BYTE Model; + BYTE Attribute; + BYTE MaxZones; + BYTE MaxSectors; + WORD MaxBlocks; + WORD MaxLogBlocks; +} *SSFDCTYPE_T; + +struct ADDRESS { + BYTE Zone; /* Zone Number */ + BYTE Sector; /* Sector(512byte) Number on Block */ + WORD PhyBlock; /* Physical Block Number on Zone */ + WORD LogBlock; /* Logical Block Number of Zone */ +}; + +typedef struct ADDRESS_T { + BYTE Zone; /* Zone Number */ + BYTE Sector; /* Sector(512byte) Number on Block */ + WORD PhyBlock; /* Physical Block Number on Zone */ + WORD LogBlock; /* Logical Block Number of Zone */ +} *ADDRESS_T; + +struct CIS_AREA { + BYTE Sector; /* Sector(512byte) Number on Block */ + WORD PhyBlock; /* Physical Block Number on Zone 0 */ +}; + + +extern BYTE IsSSFDCCompliance; +extern BYTE IsXDCompliance; + +extern DWORD ErrXDCode; +extern DWORD ErrCode; +extern WORD ReadBlock; +extern WORD WriteBlock; +extern DWORD MediaChange; + +extern struct SSFDCTYPE Ssfdc; +extern struct ADDRESS Media; +extern struct CIS_AREA CisArea; + +/* + * SMILMain.c + */ +/******************************************/ +int Init_D_SmartMedia(void); +int Pwoff_D_SmartMedia(void); +int Check_D_SmartMedia(void); +int Check_D_Parameter(struct us_data *, WORD *, BYTE *, BYTE *); +int Media_D_ReadSector(struct us_data *, DWORD, WORD, BYTE *); +int Media_D_WriteSector(struct us_data *, DWORD, WORD, BYTE *); +int Media_D_CopySector(struct us_data *, DWORD, WORD, BYTE *); +int Media_D_EraseBlock(struct us_data *, DWORD, WORD); +int Media_D_EraseAll(struct us_data *); +/******************************************/ +int Media_D_OneSectWriteStart(struct us_data *, DWORD, BYTE *); +int Media_D_OneSectWriteNext(struct us_data *, BYTE *); +int Media_D_OneSectWriteFlush(struct us_data *); + +/******************************************/ +extern int SM_FreeMem(void); /* ENE SM function */ +void SM_EnableLED(struct us_data *, BOOLEAN); +void Led_D_TernOn(void); +void Led_D_TernOff(void); + +int Media_D_EraseAllRedtData(DWORD Index, BOOLEAN 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(BYTE *); +int Check_D_FailBlock(BYTE *); +int Check_D_DataStatus(BYTE *); +int Load_D_LogBlockAddr(BYTE *); +void Clr_D_RedundantData(BYTE *); +void Set_D_LogBlockAddr(BYTE *); +void Set_D_FailBlock(BYTE *); +void Set_D_DataStaus(BYTE *); + +/******************************************/ +void Ssfdc_D_Reset(struct us_data *); +int Ssfdc_D_ReadCisSect(struct us_data *, BYTE *, BYTE *); +void Ssfdc_D_WriteRedtMode(void); +void Ssfdc_D_ReadID(BYTE *, BYTE); +int Ssfdc_D_ReadSect(struct us_data *, BYTE *, BYTE *); +int Ssfdc_D_ReadBlock(struct us_data *, WORD, BYTE *, BYTE *); +int Ssfdc_D_WriteSect(struct us_data *, BYTE *, BYTE *); +int Ssfdc_D_WriteBlock(struct us_data *, WORD, BYTE *, BYTE *); +int Ssfdc_D_CopyBlock(struct us_data *, WORD, BYTE *, BYTE *); +int Ssfdc_D_WriteSectForCopy(struct us_data *, BYTE *, BYTE *); +int Ssfdc_D_EraseBlock(struct us_data *); +int Ssfdc_D_ReadRedtData(struct us_data *, BYTE *); +int Ssfdc_D_WriteRedtData(struct us_data *, BYTE *); +int Ssfdc_D_CheckStatus(void); +int Set_D_SsfdcModel(BYTE); +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 *, BYTE *, BYTE *); + +int Ssfdc_D_ReadSect_DMA(struct us_data *, BYTE *, BYTE *); +int Ssfdc_D_ReadSect_PIO(struct us_data *, BYTE *, BYTE *); +int Ssfdc_D_WriteSect_DMA(struct us_data *, BYTE *, BYTE *); +int Ssfdc_D_WriteSect_PIO(struct us_data *, BYTE *, BYTE *); + +/******************************************/ +int Check_D_ReadError(BYTE *); +int Check_D_Correct(BYTE *, BYTE *); +int Check_D_CISdata(BYTE *, BYTE *); +void Set_D_RightECC(BYTE *); + +/* + * SMILECC.c + */ +void calculate_ecc(BYTE *, BYTE *, BYTE *, BYTE *, BYTE *); +BYTE correct_data(BYTE *, BYTE *, BYTE, BYTE, BYTE); +int _Correct_D_SwECC(BYTE *, BYTE *, BYTE *); +void _Calculate_D_SwECC(BYTE *, BYTE *); + +void SM_Init(void); + +#endif /* already included */ diff --git a/drivers/staging/keucr/smilecc.c b/drivers/staging/keucr/smilecc.c new file mode 100644 index 00000000..3085f1d4 --- /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 BYTE 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(BYTE, BYTE, BYTE *, BYTE *); + +#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(BYTE reg2, BYTE reg3, BYTE *ecc1, BYTE *ecc2) +{ + BYTE a; /* Working for reg2,reg3 */ + BYTE b; /* Working for ecc1,ecc2 */ + BYTE 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(BYTE *table, BYTE *data, BYTE *ecc1, BYTE *ecc2, BYTE *ecc3) +{ + DWORD i; /* For counting */ + BYTE a; /* Working for table */ + BYTE reg1; /* D-all,CP5,CP4,CP3,... */ + BYTE reg2; /* LP14,LP12,L10,... */ + BYTE 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 ^= (BYTE)i; /* XOR with counter */ + reg2 ^= ~((BYTE)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" + */ +BYTE correct_data(BYTE *data, BYTE *eccdata, BYTE ecc1, BYTE ecc2, BYTE ecc3) +{ + DWORD l; /* Working to check d */ + DWORD d; /* Result of comparison */ + DWORD i; /* For counting */ + BYTE d1, d2, d3; /* Result of comparison */ + BYTE a; /* Working for add */ + BYTE add; /* Byte address of cor. DATA */ + BYTE b; /* Working for bit */ + BYTE bit; /* Bit address of cor. DATA */ + + d1 = ecc1^eccdata[1]; d2 = ecc2^eccdata[0]; /* Compare LP's */ + d3 = ecc3^eccdata[2]; /* Comapre CP's */ + d = ((DWORD)d1<<16) /* Result of comparison */ + +((DWORD)d2<<8) + +(DWORD)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(BYTE *buf, BYTE *redundant_ecc, BYTE *calculate_ecc) +{ + DWORD 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(BYTE *buf, BYTE *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 00000000..cc49038e --- /dev/null +++ b/drivers/staging/keucr/smilmain.c @@ -0,0 +1,1850 @@ +#include <linux/slab.h> +#include "usb.h" +#include "scsiglue.h" +#include "smcommon.h" +#include "smil.h" + +int Check_D_LogCHS (WORD *,BYTE *,BYTE *); +void Initialize_D_Media (void); +void PowerOff_D_Media (void); +int Check_D_MediaPower (void); +int Check_D_MediaExist (void); +int Check_D_MediaWP (void); +int Check_D_MediaFmt (struct us_data *); +int Check_D_MediaFmtForEraseAll (struct us_data *); +int Conv_D_MediaAddr (struct us_data *, DWORD); +int Inc_D_MediaAddr (struct us_data *); +int Check_D_FirstSect (void); +int Check_D_LastSect (void); +int Media_D_ReadOneSect (struct us_data *, WORD, BYTE *); +int Media_D_WriteOneSect (struct us_data *, WORD, BYTE *); +int Media_D_CopyBlockHead (struct us_data *); +int Media_D_CopyBlockTail (struct us_data *); +int Media_D_EraseOneBlock (void); +int Media_D_EraseAllBlock (void); + +int Copy_D_BlockAll (struct us_data *, DWORD); +int Copy_D_BlockHead (struct us_data *); +int Copy_D_BlockTail (struct us_data *); +int Reassign_D_BlockHead (struct us_data *); + +int Assign_D_WriteBlock (void); +int Release_D_ReadBlock (struct us_data *); +int Release_D_WriteBlock (struct us_data *); +int Release_D_CopySector (struct us_data *); + +int Copy_D_PhyOneSect (struct us_data *); +int Read_D_PhyOneSect (struct us_data *, WORD, BYTE *); +int Write_D_PhyOneSect (struct us_data *, WORD, BYTE *); +int Erase_D_PhyOneBlock (struct us_data *); + +int Set_D_PhyFmtValue (struct us_data *); +int Search_D_CIS (struct us_data *); +int Make_D_LogTable (struct us_data *); +void Check_D_BlockIsFull (void); + +int MarkFail_D_PhyOneBlock (struct us_data *); + +DWORD ErrXDCode; +DWORD ErrCode; +//BYTE SectBuf[SECTSIZE]; +static BYTE WorkBuf[SECTSIZE]; +static BYTE Redundant[REDTSIZE]; +static BYTE WorkRedund[REDTSIZE]; +//WORD Log2Phy[MAX_ZONENUM][MAX_LOGBLOCK]; +static WORD *Log2Phy[MAX_ZONENUM]; // 128 x 1000, Log2Phy[MAX_ZONENUM][MAX_LOGBLOCK]; +static BYTE Assign[MAX_ZONENUM][MAX_BLOCKNUM/8]; +static WORD AssignStart[MAX_ZONENUM]; +WORD ReadBlock; +WORD WriteBlock; +DWORD MediaChange; +static DWORD SectCopyMode; + +//BIT Control Macro +static BYTE BitData[] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 } ; +#define Set_D_Bit(a,b) (a[(BYTE)((b)/8)]|= BitData[(b)%8]) +#define Clr_D_Bit(a,b) (a[(BYTE)((b)/8)]&=~BitData[(b)%8]) +#define Chk_D_Bit(a,b) (a[(BYTE)((b)/8)] & BitData[(b)%8]) + +//extern PBYTE SMHostAddr; +BYTE IsSSFDCCompliance; +BYTE IsXDCompliance; + + +// +////Power Control & Media Exist Check Function +////----- Init_D_SmartMedia() -------------------------------------------- +//int Init_D_SmartMedia(void) +//{ +// int i; +// +// EMCR_Print("Init_D_SmartMedia start\n"); +// for (i=0; i<MAX_ZONENUM; i++) +// { +// if (Log2Phy[i]!=NULL) +// { +// EMCR_Print("ExFreePool Zone = %x, Addr = %x\n", i, Log2Phy[i]); +// ExFreePool(Log2Phy[i]); +// Log2Phy[i] = NULL; +// } +// } +// +// Initialize_D_Media(); +// return(NO_ERROR); +//} + +//----- 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); +} + +////----- Pwoff_D_SmartMedia() ------------------------------------------- +//int Pwoff_D_SmartMedia(void) +//{ +// PowerOff_D_Media(); +// return(NO_ERROR); +//} +// +////----- Check_D_SmartMedia() ------------------------------------------- +//int Check_D_SmartMedia(void) +//{ +// if (Check_D_MediaExist()) +// return(ErrCode); +// +// return(NO_ERROR); +//} +// +////----- Check_D_Parameter() -------------------------------------------- +//int Check_D_Parameter(PFDO_DEVICE_EXTENSION fdoExt,WORD *pcyl,BYTE *phead,BYTE *psect) +//{ +// if (Check_D_MediaPower()) +// return(ErrCode); +// +// if (Check_D_MediaFmt(fdoExt)) +// return(ErrCode); +// +// if (Check_D_LogCHS(pcyl,phead,psect)) +// return(ErrCode); +// +// return(NO_ERROR); +//} + +//SmartMedia Read/Write/Erase Function +//----- Media_D_ReadSector() ------------------------------------------- +int Media_D_ReadSector(struct us_data *us, DWORD start,WORD count,BYTE *buf) +{ + WORD len, bn; + + //if (Check_D_MediaPower()) ; ¦b 6250 don't care + // return(ErrCode); + //if (Check_D_MediaFmt(fdoExt)) ; + // return(ErrCode); + 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(fdoExt, SectBuf)) + //if (Media_D_ReadOneSect(fdoExt, count, buf)) + 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, DWORD start,WORD count,BYTE *buf) +{ + //DWORD mode; + //int i; + WORD len, bn; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + /* 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(fdoExt,count,buf,Redundant)) + if (Ssfdc_D_CopyBlock(us,bn,buf,Redundant)) + { + ErrCode = ERR_WriteFault; + return(ErrCode); + } + + Media.Sector = 0x1F; + //if (Release_D_ReadBlock(fdoExt)) + 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); +} + +//----- Release_D_CopySector() ------------------------------------------ +int Release_D_CopySector(struct us_data *us) +{ + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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); +} +/* +//----- Media_D_WriteSector() ------------------------------------------ +int Media_D_WriteSector(PFDO_DEVICE_EXTENSION fdoExt, DWORD start,WORD count,BYTE *buf) +{ + int i; + WORD len, bn; + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + //if (Check_D_MediaPower()) + // return(ErrCode); + // + //if (Check_D_MediaFmt(fdoExt)) + // return(ErrCode); + // + //if (Check_D_MediaWP()) + // return(ErrCode); + + if (Conv_D_MediaAddr(fdoExt, start)) + return(ErrCode); + + //ENE_Print("Media_D_WriteSector --- Sector = %x\n", Media.Sector); + if (Check_D_FirstSect()) + { + if (Media_D_CopyBlockHead(fdoExt)) + { + ErrCode = ERR_WriteFault; + return(ErrCode); + } + } + + while(1) + { + if (!Check_D_FirstSect()) + { + if (Assign_D_WriteBlock()) + return(ErrCode); + } + + len = Ssfdc.MaxSectors - Media.Sector; + if (count > len) + bn = len; + else + bn = count; + //for(i=0;i<SECTSIZE;i++) + // SectBuf[i]=*buf++; + + //if (Media_D_WriteOneSect(fdoExt, SectBuf)) + if (Media_D_WriteOneSect(fdoExt, bn, buf)) + { + ErrCode = ERR_WriteFault; + return(ErrCode); + } + + Media.Sector += bn - 1; + + if (!Check_D_LastSect()) + { + if (Release_D_ReadBlock(fdoExt)) + + { if (ErrCode==ERR_HwError) + { + ErrCode = ERR_WriteFault; + return(ErrCode); + } + } + } + + count -= bn; + + if (count<=0) + break; + + buf += bn * SECTSIZE; + + //if (--count<=0) + // break; + + if (Inc_D_MediaAddr(fdoExt)) + return(ErrCode); + } + + if (!Check_D_LastSect()) + return(NO_ERROR); + + if (Inc_D_MediaAddr(fdoExt)) + return(ErrCode); + + if (Media_D_CopyBlockTail(fdoExt)) + { + ErrCode = ERR_WriteFault; + return(ErrCode); + } + + return(NO_ERROR); +} +// +////----- Media_D_EraseBlock() ------------------------------------------- +//int Media_D_EraseBlock(PFDO_DEVICE_EXTENSION fdoExt, DWORD start,WORD count) +//{ +// if (Check_D_MediaPower()) +// return(ErrCode); +// +// if (Check_D_MediaFmt(fdoExt)) +// return(ErrCode); +// +// if (Check_D_MediaWP()) +// return(ErrCode); +// +// if (Conv_D_MediaAddr(start)) +// return(ErrCode); +// +// while(Check_D_FirstSect()) { +// if (Inc_D_MediaAddr(fdoExt)) +// return(ErrCode); +// +// if (--count<=0) +// return(NO_ERROR); +// } +// +// while(1) { +// if (!Check_D_LastSect()) +// if (Media_D_EraseOneBlock()) +// if (ErrCode==ERR_HwError) +// { +// ErrCode = ERR_WriteFault; +// return(ErrCode); +// } +// +// if (Inc_D_MediaAddr(fdoExt)) +// return(ErrCode); +// +// if (--count<=0) +// return(NO_ERROR); +// } +//} +// +////----- Media_D_EraseAll() --------------------------------------------- +//int Media_D_EraseAll(PFDO_DEVICE_EXTENSION fdoExt) +//{ +// if (Check_D_MediaPower()) +// return(ErrCode); +// +// if (Check_D_MediaFmtForEraseAll(fdoExt)) +// return(ErrCode); +// +// if (Check_D_MediaWP()) +// return(ErrCode); +// +// if (Media_D_EraseAllBlock()) +// return(ErrCode); +// +// return(NO_ERROR); +//} + +//SmartMedia Write Function for One Sector Write Mode +//----- Media_D_OneSectWriteStart() ------------------------------------ +int Media_D_OneSectWriteStart(PFDO_DEVICE_EXTENSION fdoExt,DWORD start,BYTE *buf) +{ +// int i; +// SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; +// ADDRESS_T bb = (ADDRESS_T) &Media; +// +// //if (Check_D_MediaPower()) +// // return(ErrCode); +// //if (Check_D_MediaFmt(fdoExt)) +// // return(ErrCode); +// //if (Check_D_MediaWP()) +// // return(ErrCode); +// if (Conv_D_MediaAddr(fdoExt, start)) +// return(ErrCode); +// +// if (Check_D_FirstSect()) +// if (Media_D_CopyBlockHead(fdoExt)) +// { +// ErrCode = ERR_WriteFault; +// return(ErrCode); +// } +// +// if (!Check_D_FirstSect()) +// if (Assign_D_WriteBlock()) +// return(ErrCode); +// +// //for(i=0;i<SECTSIZE;i++) +// // SectBuf[i]=*buf++; +// +// //if (Media_D_WriteOneSect(fdoExt, SectBuf)) +// if (Media_D_WriteOneSect(fdoExt, buf)) +// { +// ErrCode = ERR_WriteFault; +// return(ErrCode); +// } +// +// if (!Check_D_LastSect()) +// { +// if (Release_D_ReadBlock(fdoExt)) +// if (ErrCode==ERR_HwError) +// { +// ErrCode = ERR_WriteFault; +// return(ErrCode); +// } +// } + + return(NO_ERROR); +} + +//----- Media_D_OneSectWriteNext() ------------------------------------- +int Media_D_OneSectWriteNext(PFDO_DEVICE_EXTENSION fdoExt, BYTE *buf) +{ +// int i; +// SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; +// ADDRESS_T bb = (ADDRESS_T) &Media; +// +// if (Inc_D_MediaAddr(fdoExt)) +// return(ErrCode); +// +// if (!Check_D_FirstSect()) +// if (Assign_D_WriteBlock()) +// return(ErrCode); +// +// //for(i=0;i<SECTSIZE;i++) +// // SectBuf[i]=*buf++; +// +// //if (Media_D_WriteOneSect(fdoExt, SectBuf)) +// if (Media_D_WriteOneSect(fdoExt, buf)) +// { +// ErrCode = ERR_WriteFault; +// return(ErrCode); +// } +// +// if (!Check_D_LastSect()) +// { +// if (Release_D_ReadBlock(fdoExt)) +// if (ErrCode==ERR_HwError) +// { +// ErrCode = ERR_WriteFault; +// return(ErrCode); +// } +// } + + return(NO_ERROR); +} + +//----- Media_D_OneSectWriteFlush() ------------------------------------ +int Media_D_OneSectWriteFlush(PFDO_DEVICE_EXTENSION fdoExt) +{ + if (!Check_D_LastSect()) + return(NO_ERROR); + + if (Inc_D_MediaAddr(fdoExt)) + return(ErrCode); + + if (Media_D_CopyBlockTail(fdoExt)) + { + ErrCode = ERR_WriteFault; + return(ErrCode); + } + + return(NO_ERROR); +} +// +////LED Tern On/Off Subroutine +////----- SM_EnableLED() ----------------------------------------------- +//void SM_EnableLED(PFDO_DEVICE_EXTENSION fdoExt, BOOLEAN enable) +//{ +// if (fdoExt->Drive_IsSWLED) +// { +// if (enable) +// Led_D_TernOn(); +// else +// Led_D_TernOff(); +// } +//} +// +////----- Led_D_TernOn() ------------------------------------------------- +//void Led_D_TernOn(void) +//{ +// if (Check_D_CardStsChg()) +// MediaChange=ERROR; +// +// Cnt_D_LedOn(); +//} +// +////----- Led_D_TernOff() ------------------------------------------------ +//void Led_D_TernOff(void) +//{ +// if (Check_D_CardStsChg()) +// MediaChange=ERROR; +// +// Cnt_D_LedOff(); +//} +// +////SmartMedia Logical Format Subroutine +////----- Check_D_LogCHS() ----------------------------------------------- +//int Check_D_LogCHS(WORD *c,BYTE *h,BYTE *s) +//{ +// switch(Ssfdc.Model) { +// case SSFDC1MB: *c=125; *h= 4; *s= 4; break; +// case SSFDC2MB: *c=125; *h= 4; *s= 8; break; +// case SSFDC4MB: *c=250; *h= 4; *s= 8; break; +// case SSFDC8MB: *c=250; *h= 4; *s=16; break; +// case SSFDC16MB: *c=500; *h= 4; *s=16; break; +// case SSFDC32MB: *c=500; *h= 8; *s=16; break; +// case SSFDC64MB: *c=500; *h= 8; *s=32; break; +// case SSFDC128MB: *c=500; *h=16; *s=32; break; +// default: *c= 0; *h= 0; *s= 0; ErrCode = ERR_NoSmartMedia; return(ERROR); +// } +// +// return(SMSUCCESS); +//} +// +////Power Control & Media Exist Check Subroutine +////----- Initialize_D_Media() ------------------------------------------- +//void Initialize_D_Media(void) +//{ +// ErrCode = NO_ERROR; +// MediaChange = ERROR; +// SectCopyMode = COMPLETED; +// Cnt_D_Reset(); +//} +// +////----- PowerOff_D_Media() --------------------------------------------- +//void PowerOff_D_Media(void) +//{ +// Cnt_D_PowerOff(); +//} +// +////----- Check_D_MediaPower() ------------------------------------------- +//int Check_D_MediaPower(void) +//{ +// //usleep(56*1024); +// if (Check_D_CardStsChg()) +// MediaChange = ERROR; +// //usleep(56*1024); +// if ((!Check_D_CntPower())&&(!MediaChange)) // ¦³ power & Media ¨S³Q change, «h return success +// return(SMSUCCESS); +// //usleep(56*1024); +// +// if (Check_D_CardExist()) // Check if card is not exist, return err +// { +// ErrCode = ERR_NoSmartMedia; +// MediaChange = ERROR; +// return(ERROR); +// } +// //usleep(56*1024); +// if (Cnt_D_PowerOn()) +// { +// ErrCode = ERR_NoSmartMedia; +// MediaChange = ERROR; +// return(ERROR); +// } +// //usleep(56*1024); +// Ssfdc_D_Reset(fdoExt); +// //usleep(56*1024); +// return(SMSUCCESS); +//} +// +////-----Check_D_MediaExist() -------------------------------------------- +//int Check_D_MediaExist(void) +//{ +// if (Check_D_CardStsChg()) +// MediaChange = ERROR; +// +// if (!Check_D_CardExist()) +// { +// if (!MediaChange) +// return(SMSUCCESS); +// +// ErrCode = ERR_ChangedMedia; +// return(ERROR); +// } +// +// ErrCode = ERR_NoSmartMedia; +// +// return(ERROR); +//} +// +////----- Check_D_MediaWP() ---------------------------------------------- +//int Check_D_MediaWP(void) +//{ +// if (Ssfdc.Attribute &MWP) +// { +// ErrCode = ERR_WrtProtect; +// return(ERROR); +// } +// +// return(SMSUCCESS); +//} +*/ +//SmartMedia Physical Format Test Subroutine +//----- Check_D_MediaFmt() --------------------------------------------- +int Check_D_MediaFmt(struct us_data *us) +{ + pr_info("Check_D_MediaFmt\n"); + //ULONG i,j, result=FALSE, zone,block; + + //usleep(56*1024); + if (!MediaChange) + return(SMSUCCESS); + + MediaChange = ERROR; + SectCopyMode = COMPLETED; + + //usleep(56*1024); + if (Set_D_PhyFmtValue(us)) + { + ErrCode = ERR_UnknownMedia; + return(ERROR); + } + + //usleep(56*1024); + if (Search_D_CIS(us)) + { + ErrCode = ERR_IllegalFmt; + return(ERROR); + } + + + MediaChange = SMSUCCESS; + return(SMSUCCESS); +} +/* +////----- Check_D_BlockIsFull() ---------------------------------- +//void Check_D_BlockIsFull() +//{ +// ULONG i, block; +// +// if (IsXDCompliance || IsSSFDCCompliance) +// { +// // If the blocks are full then return write-protect. +// block = Ssfdc.MaxBlocks/8; +// for (Media.Zone=0; Media.Zone<Ssfdc.MaxZones; Media.Zone++) +// { +// if (Log2Phy[Media.Zone]==NULL) +// { +// if (Make_D_LogTable()) +// { +// ErrCode = ERR_IllegalFmt; +// return; +// } +// } +// +// for (i=0; i<block; i++) +// { +// if (Assign[Media.Zone][i] != 0xFF) +// return; +// } +// } +// Ssfdc.Attribute |= WP; +// } +//} +// +// +////----- Check_D_MediaFmtForEraseAll() ---------------------------------- +//int Check_D_MediaFmtForEraseAll(PFDO_DEVICE_EXTENSION fdoExt) +//{ +// MediaChange = ERROR; +// SectCopyMode = COMPLETED; +// +// if (Set_D_PhyFmtValue(fdoExt)) +// { +// ErrCode = ERR_UnknownMedia; +// return(ERROR); +// } +// +// if (Search_D_CIS(fdoExt)) +// { +// ErrCode = ERR_IllegalFmt; +// return(ERROR); +// } +// +// return(SMSUCCESS); +//} +*/ +//SmartMedia Physical Address Control Subroutine +//----- Conv_D_MediaAddr() --------------------------------------------- +int Conv_D_MediaAddr(struct us_data *us, DWORD addr) +{ + DWORD temp; + //ULONG zz; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + temp = addr/Ssfdc.MaxSectors; + Media.Zone = (BYTE) (temp/Ssfdc.MaxLogBlocks); + + if (Log2Phy[Media.Zone]==NULL) + { + if (Make_D_LogTable(us)) + { + ErrCode = ERR_IllegalFmt; + return(ERROR); + } + } + + Media.Sector = (BYTE) (addr%Ssfdc.MaxSectors); + Media.LogBlock = (WORD) (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() ---------------------------------------------- +int Inc_D_MediaAddr(struct us_data *us) +{ + WORD LogBlock = Media.LogBlock; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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); +} +/* +//----- Check_D_FirstSect() -------------------------------------------- +int Check_D_FirstSect(void) +{ + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + if (!Media.Sector) + return(SMSUCCESS); + + return(ERROR); +} + +//----- Check_D_LastSect() --------------------------------------------- +int Check_D_LastSect(void) +{ + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + if (Media.Sector<(Ssfdc.MaxSectors-1)) + return(ERROR); + + return(SMSUCCESS); +} +*/ +//SmartMedia Read/Write Subroutine with Retry +//----- Media_D_ReadOneSect() ------------------------------------------ +int Media_D_ReadOneSect(struct us_data *us, WORD count, BYTE *buf) +{ + DWORD 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); +} +/* +//----- Media_D_WriteOneSect() ----------------------------------------- +int Media_D_WriteOneSect(PFDO_DEVICE_EXTENSION fdoExt, WORD count, BYTE *buf) +{ + DWORD retry; + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + if (!Write_D_PhyOneSect(fdoExt, count, buf)) + return(SMSUCCESS); + if (ErrCode==ERR_HwError) + return(ERROR); + + for(retry=1; retry<2; retry++) + { + if (Reassign_D_BlockHead(fdoExt)) + { + if (ErrCode==ERR_HwError) + return(ERROR); + continue; + } + + if (!Write_D_PhyOneSect(fdoExt, count, buf)) + return(SMSUCCESS); + if (ErrCode==ERR_HwError) + return(ERROR); + } + + if (Release_D_WriteBlock(fdoExt)) + return(ERROR); + + ErrCode = ERR_WriteFault; + MediaChange = ERROR; + return(ERROR); +} + +//SmartMedia Data Copy Subroutine with Retry +//----- Media_D_CopyBlockHead() ---------------------------------------- +int Media_D_CopyBlockHead(PFDO_DEVICE_EXTENSION fdoExt) +{ + DWORD retry; + + for(retry=0; retry<2; retry++) + { + if (!Copy_D_BlockHead(fdoExt)) + return(SMSUCCESS); + if (ErrCode==ERR_HwError) + return(ERROR); + } + + MediaChange = ERROR; + return(ERROR); +} + +//----- Media_D_CopyBlockTail() ---------------------------------------- +int Media_D_CopyBlockTail(PFDO_DEVICE_EXTENSION fdoExt) +{ + DWORD retry; + + if (!Copy_D_BlockTail(fdoExt)) + return(SMSUCCESS); + if (ErrCode==ERR_HwError) + return(ERROR); + + for(retry=1; retry<2; retry++) + { + if (Reassign_D_BlockHead(fdoExt)) + { + if (ErrCode==ERR_HwError) + return(ERROR); + continue; + } + + if (!Copy_D_BlockTail(fdoExt)) + return(SMSUCCESS); + if (ErrCode==ERR_HwError) + return(ERROR); + } + + if (Release_D_WriteBlock(fdoExt)) + return(ERROR); + + ErrCode = ERR_WriteFault; + MediaChange = ERROR; + return(ERROR); +} +// +////----- Media_D_EraseOneBlock() ---------------------------------------- +//int Media_D_EraseOneBlock(void) +//{ +// WORD LogBlock = Media.LogBlock; +// WORD PhyBlock = Media.PhyBlock; +// SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; +// ADDRESS_T bb = (ADDRESS_T) &Media; +// +// if (Media.PhyBlock==NO_ASSIGN) +// return(SMSUCCESS); +// +// if (Log2Phy[Media.Zone]==NULL) +// { +// if (Make_D_LogTable()) +// { +// ErrCode = ERR_IllegalFmt; +// return(ERROR); +// } +// } +// Media.LogBlock = LogBlock; +// Media.PhyBlock = PhyBlock; +// +// Log2Phy[Media.Zone][Media.LogBlock]=NO_ASSIGN; +// +// if (Erase_D_PhyOneBlock(fdoExt)) +// { +// if (ErrCode==ERR_HwError) +// return(ERROR); +// if (MarkFail_D_PhyOneBlock()) +// return(ERROR); +// +// ErrCode = ERR_WriteFault; +// return(ERROR); +// } +// +// Clr_D_Bit(Assign[Media.Zone],Media.PhyBlock); +// Media.PhyBlock=NO_ASSIGN; +// return(SMSUCCESS); +//} +// +////SmartMedia Erase Subroutine +////----- Media_D_EraseAllBlock() ---------------------------------------- +//int Media_D_EraseAllBlock(void) +//{ +// WORD cis=0; +// +// SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; +// ADDRESS_T bb = (ADDRESS_T) &Media; +// +// MediaChange = ERROR; +// Media.Sector = 0; +// +// for(Media.Zone=0; Media.Zone<Ssfdc.MaxZones; Media.Zone++) +// for(Media.PhyBlock=0; Media.PhyBlock<Ssfdc.MaxBlocks; Media.PhyBlock++) { +// if (Ssfdc_D_ReadRedtData(Redundant)) +// { +// Ssfdc_D_Reset(fdoExt); +// return(ERROR); +// } +// +// Ssfdc_D_Reset(fdoExt); +// if (!Check_D_FailBlock(Redundant)) +// { +// if (cis) +// { +// if (Ssfdc_D_EraseBlock(fdoExt)) +// { +// ErrCode = ERR_HwError; +// return(ERROR); +// } +// +// if (Ssfdc_D_CheckStatus()) +// { +// if (MarkFail_D_PhyOneBlock()) +// return(ERROR); +// } +// +// continue; +// } +// +// if (Media.PhyBlock!=CisArea.PhyBlock) +// { +// ErrCode = ERR_IllegalFmt; +// return(ERROR); +// } +// +// cis++; +// } +// +// } +// return(SMSUCCESS); +//} +*/ +//SmartMedia Physical Sector Data Copy Subroutine +//----- Copy_D_BlockAll() ---------------------------------------------- +int Copy_D_BlockAll(struct us_data *us, DWORD mode) +{ + BYTE sect; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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); +} +/* +//----- Copy_D_BlockHead() --------------------------------------------- +int Copy_D_BlockHead(PFDO_DEVICE_EXTENSION fdoExt) +{ + BYTE sect; + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + sect=Media.Sector; + if (Assign_D_WriteBlock()) + return(ERROR); + + for(Media.Sector=0; Media.Sector<sect; Media.Sector++) + { + if (Copy_D_PhyOneSect(fdoExt)) + { + if (ErrCode==ERR_HwError) + return(ERROR); + if (Release_D_WriteBlock(fdoExt)) + return(ERROR); + + ErrCode = ERR_WriteFault; + Media.PhyBlock=ReadBlock; + Media.Sector=sect; + + return(ERROR); + } + } + + Media.PhyBlock=WriteBlock; + Media.Sector=sect; + return(SMSUCCESS); +} + +//----- Copy_D_BlockTail() --------------------------------------------- +int Copy_D_BlockTail(PFDO_DEVICE_EXTENSION fdoExt) +{ + BYTE sect; + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + for(sect=Media.Sector; Media.Sector<Ssfdc.MaxSectors; Media.Sector++) + { + if (Copy_D_PhyOneSect(fdoExt)) + { + if (ErrCode==ERR_HwError) + return(ERROR); + + Media.PhyBlock=WriteBlock; + Media.Sector=sect; + + return(ERROR); + } + } + + if (Release_D_ReadBlock(fdoExt)) + return(ERROR); + + Media.PhyBlock=WriteBlock; + Media.Sector=sect; + return(SMSUCCESS); +} + +//----- Reassign_D_BlockHead() ----------------------------------------- +int Reassign_D_BlockHead(PFDO_DEVICE_EXTENSION fdoExt) +{ + DWORD mode; + WORD block; + BYTE sect; + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + mode=SectCopyMode; + block=ReadBlock; + sect=Media.Sector; + + if (Assign_D_WriteBlock()) + return(ERROR); + + SectCopyMode=REQ_FAIL; + + for(Media.Sector=0; Media.Sector<sect; Media.Sector++) + { + if (Copy_D_PhyOneSect(fdoExt)) + { + if (ErrCode==ERR_HwError) + return(ERROR); + if (Release_D_WriteBlock(fdoExt)) + return(ERROR); + + ErrCode = ERR_WriteFault; + SectCopyMode=mode; + WriteBlock=ReadBlock; + ReadBlock=block; + Media.Sector=sect; + Media.PhyBlock=WriteBlock; + + return(ERROR); + } + } + + if (Release_D_ReadBlock(fdoExt)) + return(ERROR); + + SectCopyMode=mode; + ReadBlock=block; + Media.Sector=sect; + Media.PhyBlock=WriteBlock; + return(SMSUCCESS); +} +*/ +//SmartMedia Physical Block Assign/Release Subroutine +//----- Assign_D_WriteBlock() ------------------------------------------ +int Assign_D_WriteBlock(void) +{ + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + 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; + //ErrXDCode = NO_ERROR; + 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; + //ErrXDCode = NO_ERROR; + return(SMSUCCESS); + } + } + + WriteBlock=NO_ASSIGN; + ErrCode = ERR_WriteFault; + // For xD test + //Ssfdc.Attribute |= WP; + //ErrXDCode = ERR_WrtProtect; + return(ERROR); +} + +//----- Release_D_ReadBlock() ------------------------------------------ +int Release_D_ReadBlock(struct us_data *us) +{ + DWORD mode; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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() ----------------------------------------- +int Release_D_WriteBlock(struct us_data *us) +{ + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + 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() -------------------------------------------- +int Copy_D_PhyOneSect(struct us_data *us) +{ + int i; + DWORD err, retry; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + /* pr_info("Copy_D_PhyOneSect --- Secotr = %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() -------------------------------------------- +int Read_D_PhyOneSect(struct us_data *us, WORD count, BYTE *buf) +{ + int i; + DWORD retry; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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_ReadSect(fdoExt,buf,Redundant)) + 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); +} +/* +//----- Write_D_PhyOneSect() ------------------------------------------- +int Write_D_PhyOneSect(PFDO_DEVICE_EXTENSION fdoExt, WORD count, BYTE *buf) +{ + SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + ADDRESS_T bb = (ADDRESS_T) &Media; + + //if (Ssfdc_D_WriteSect(fdoExt,buf,Redundant)) + if (Ssfdc_D_WriteBlock(fdoExt,count,buf,Redundant)) + { ErrCode = ERR_HwError; MediaChange=ERROR; return(ERROR); } + if (Ssfdc_D_CheckStatus()) + { ErrCode = ERR_WriteFault; return(ERROR); } + + return(SMSUCCESS); +} +*/ +//----- Erase_D_PhyOneBlock() ------------------------------------------ +int Erase_D_PhyOneBlock(struct us_data *us) +{ + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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() -------------------------------------------- +int Set_D_PhyFmtValue(struct us_data *us) +{ +// PPDO_DEVICE_EXTENSION pdoExt; +// BYTE idcode[4]; +// DWORD UserDefData_1, UserDefData_2, Data, mask; +// +// //if (!fdoExt->ChildDeviceObject) return(ERROR); +// //pdoExt = fdoExt->ChildDeviceObject->DeviceExtension; +// +// Ssfdc_D_ReadID(idcode, READ_ID_1); +// + //if (Set_D_SsfdcModel(idcode[1])) + if (Set_D_SsfdcModel(us->SM_DeviceID)) + return(ERROR); + +// //Use Multi-function pin to differentiate SM and xD. +// UserDefData_1 = ReadPCIReg(fdoExt->BusID, fdoExt->DevID, fdoExt->FuncID, PCI_REG_USER_DEF) & 0x80; +// if (UserDefData_1) +// { +// if ( READ_PORT_BYTE(SM_REG_INT_STATUS) & 0x80 ) fdoExt->DiskType = DISKTYPE_XD; +// if ( READ_PORT_BYTE(SM_REG_INT_STATUS) & 0x40 ) fdoExt->DiskType = DISKTYPE_SM; +// +// if ( IsXDCompliance && (fdoExt->DiskType == DISKTYPE_XD) ) +// { +// Ssfdc_D_ReadID(idcode, READ_ID_3); +// if (idcode[2] != 0xB5) +// return(ERROR); +// } +// } +// +// //Use GPIO to differentiate SM and xD. +// UserDefData_2 = ReadPCIReg(fdoExt->BusID, fdoExt->DevID, fdoExt->FuncID, PCI_REG_USER_DEF) >> 8; +// if ( UserDefData_2 ) +// { +// Data = ReadPCIReg(fdoExt->BusID, fdoExt->DevID, 0, 0xAC); +// +// mask = 1 << (UserDefData_2-1); +// // 1 : xD , 0 : SM +// if ( Data & mask) +// fdoExt->DiskType = DISKTYPE_XD; +// else +// fdoExt->DiskType = DISKTYPE_SM; +// +// if ( IsXDCompliance && (fdoExt->DiskType == DISKTYPE_XD) ) +// { +// Ssfdc_D_ReadID(idcode, READ_ID_3); +// if (idcode[2] != 0xB5) +// return(ERROR); +// } +// } +// +// if ( !(UserDefData_1 | UserDefData_2) ) +// { +// // Use UserDefine Register to differentiate SM and xD. +// Ssfdc_D_ReadID(idcode, READ_ID_3); +// +// if (idcode[2] == 0xB5) +// fdoExt->DiskType = DISKTYPE_XD; +// else +// { +// if (!IsXDCompliance) +// fdoExt->DiskType = DISKTYPE_SM; +// else +// return(ERROR); +// } +// +// if (fdoExt->UserDef_DiskType == 0x04) fdoExt->DiskType = DISKTYPE_XD; +// if (fdoExt->UserDef_DiskType == 0x08) fdoExt->DiskType = DISKTYPE_SM; +// } +// +// if (!fdoExt->UserDef_DisableWP) +// { +// if (fdoExt->DiskType == DISKTYPE_SM) +// { +// if (Check_D_SsfdcWP()) +// Ssfdc.Attribute|=WP; +// } +// } + + return(SMSUCCESS); +} + +//----- Search_D_CIS() ------------------------------------------------- +int Search_D_CIS(struct us_data *us) +{ + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + 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() ---------------------------------------------- +int Make_D_LogTable(struct us_data *us) +{ + WORD phyblock,logblock; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + if (Log2Phy[Media.Zone]==NULL) + { + Log2Phy[Media.Zone] = kmalloc(MAX_LOGBLOCK*sizeof(WORD), 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; + + //for(Media.Zone=0; Media.Zone<MAX_ZONENUM; Media.Zone++) + //for(Media.Zone=0; Media.Zone<Ssfdc.MaxZones; Media.Zone++) + { + /* 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 (Check_D_DataStatus(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 = (BYTE)(Ssfdc.MaxSectors-1); + + if (Ssfdc_D_ReadRedtData(us, Redundant)) + { Ssfdc_D_Reset(us); return(ERROR); } + + if (!Load_D_LogBlockAddr(Redundant)) + { + if (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; + +// here Not yet +//#ifdef L2P_ERR_ERASE +// if (!(Ssfdc.Attribute &MWP)) +// { +// Ssfdc_D_Reset(fdoExt); +// if (Ssfdc_D_EraseBlock(fdoExt)) +// return(ERROR); +// +// if (Ssfdc_D_CheckStatus()) +// { +// if (MarkFail_D_PhyOneBlock()) +// return(ERROR); +// } +// else +// Clr_D_Bit(Assign[Media.Zone],Media.PhyBlock); +// } +//#else +// Ssfdc.Attribute|=MWP; +//#endif + Media.PhyBlock=phyblock; + + } // End for (Media.PhyBlock<Ssfdc.MaxBlocks) + + AssignStart[Media.Zone]=0; + + } // End for (Media.Zone<MAX_ZONENUM) + + Ssfdc_D_Reset(us); + return(SMSUCCESS); +} + +//----- MarkFail_D_PhyOneBlock() --------------------------------------- +int MarkFail_D_PhyOneBlock(struct us_data *us) +{ + BYTE sect; + //SSFDCTYPE_T aa = (SSFDCTYPE_T ) &Ssfdc; + //ADDRESS_T bb = (ADDRESS_T) &Media; + + sect=Media.Sector; + Set_D_FailBlock(WorkRedund); + //Ssfdc_D_WriteRedtMode(); + + 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); +} +/* +// +////----- SM_Init() ---------------------------------------------------- +//void SM_Init(void) +//{ +// _Hw_D_ClrIntCardChg(); +// _Hw_D_SetIntMask(); +// // For DMA Interrupt +// _Hw_D_ClrDMAIntCardChg(); +// _Hw_D_SetDMAIntMask(); +//} +// +////----- Media_D_EraseAllRedtData() ----------------------------------- +//int Media_D_EraseAllRedtData(DWORD Index, BOOLEAN CheckBlock) +//{ +// BYTE i; +// +// if (Check_D_MediaPower()) +// return(ErrCode); +// +// if (Check_D_MediaWP()) +// return(ErrCode); +// +// for (i=0; i<REDTSIZE; i++) +// WorkRedund[i] = 0xFF; +// +// Media.Zone = (BYTE)Index; +// for (Media.PhyBlock=0; Media.PhyBlock<Ssfdc.MaxBlocks; Media.PhyBlock++) +// { +// if ((!Media.Zone) && (Media.PhyBlock<=CisArea.PhyBlock)) +// continue; +// +// if (Ssfdc_D_EraseBlock(fdoExt)) +// { +// ErrCode = ERR_HwError; +// return(ERROR); +// } +// +// for(Media.Sector=0; Media.Sector<Ssfdc.MaxSectors; Media.Sector++) +// { +// Ssfdc_D_WriteRedtMode(); +// +// if (Ssfdc_D_WriteRedtData(WorkRedund)) +// { +// Ssfdc_D_Reset(fdoExt); +// ErrCode = ERR_HwError; +// MediaChange = ERROR; +// return(ERROR); +// } // NO Status Check +// } +// +// Ssfdc_D_Reset(fdoExt); +// } +// +// Ssfdc_D_Reset(fdoExt); +// +// return(SMSUCCESS); +//} +// +////----- Media_D_GetMediaInfo() --------------------------------------- +//DWORD Media_D_GetMediaInfo(PFDO_DEVICE_EXTENSION fdoExt, PIOCTL_MEDIA_INFO_IN pParamIn, PIOCTL_MEDIA_INFO_OUT pParamOut) +//{ +// pParamOut->ErrCode = STATUS_CMD_FAIL; +// +// Init_D_SmartMedia(); +// +// if (Check_D_MediaPower()) +// return (ErrCode==ERR_NoSmartMedia) ? STATUS_CMD_NO_MEDIA : STATUS_CMD_FAIL; +// +// if (Set_D_PhyFmtValue(fdoExt)) +// return STATUS_CMD_FAIL; +// +// //usleep(56*1024); +// if (Search_D_CIS(fdoExt)) +// return STATUS_CMD_FAIL; +// +// if (Check_D_MediaWP()) +// return STATUS_CMD_MEDIA_WP; +// +// pParamOut->PageSize = Ssfdc.MaxSectors; +// pParamOut->BlockSize = Ssfdc.MaxBlocks; +// pParamOut->ZoneSize = Ssfdc.MaxZones; +// +// return STATUS_CMD_SUCCESS; +//}*/ diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c new file mode 100644 index 00000000..d4dd5ed5 --- /dev/null +++ b/drivers/staging/keucr/smilsub.c @@ -0,0 +1,693 @@ +#include <linux/slab.h> +#include "usb.h" +#include "scsiglue.h" +#include "transport.h" + +#include "smcommon.h" +#include "smil.h" + +void _Set_D_SsfdcRdCmd(BYTE); +void _Set_D_SsfdcRdAddr(BYTE); +void _Set_D_SsfdcRdChip(void); +void _Set_D_SsfdcRdStandby(void); +void _Start_D_SsfdcRdHwECC(void); +void _Stop_D_SsfdcRdHwECC(void); +void _Load_D_SsfdcRdHwECC(BYTE); +void _Set_D_SsfdcWrCmd(BYTE); +void _Set_D_SsfdcWrAddr(BYTE); +void _Set_D_SsfdcWrBlock(void); +void _Set_D_SsfdcWrStandby(void); +void _Start_D_SsfdcWrHwECC(void); +void _Load_D_SsfdcWrHwECC(BYTE); +int _Check_D_SsfdcBusy(WORD); +int _Check_D_SsfdcStatus(void); +void _Reset_D_SsfdcErr(void); +void _Read_D_SsfdcBuf(BYTE *); +void _Write_D_SsfdcBuf(BYTE *); +void _Read_D_SsfdcByte(BYTE *); +void _ReadRedt_D_SsfdcBuf(BYTE *); +void _WriteRedt_D_SsfdcBuf(BYTE *); +BYTE _Check_D_DevCode(BYTE); + +void _Set_D_ECCdata(BYTE, BYTE *); +void _Calc_D_ECCdata(BYTE *); + + +struct SSFDCTYPE Ssfdc; +struct ADDRESS Media; +struct CIS_AREA CisArea; + +static BYTE EccBuf[6]; +extern PBYTE SMHostAddr; +extern DWORD ErrXDCode; + +extern WORD ReadBlock; +extern WORD WriteBlock; + + + +#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(BYTE *redundant) +{ + char i; + + for (i = 0; i < REDTSIZE; i++) + if (*redundant++ != 0xFF) + return ERROR; + + return SMSUCCESS; +} + +/* ----- Check_D_FailBlock() -------------------------------------------- */ +int Check_D_FailBlock(BYTE *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(BYTE *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(BYTE *redundant) +{ + WORD addr1, addr2; + + addr1 = (WORD)*(redundant + REDT_ADDR1H)*0x0100 + (WORD)*(redundant + REDT_ADDR1L); + addr2 = (WORD)*(redundant + REDT_ADDR2H)*0x0100 + (WORD)*(redundant + REDT_ADDR2L); + + if (addr1 == addr2) + if ((addr1 & 0xF000) == 0x1000) { + Media.LogBlock = (addr1 & 0x0FFF) / 2; + return SMSUCCESS; + } + + if (hweight16((WORD)(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(BYTE *redundant) +{ + char i; + + for (i = 0; i < REDTSIZE; i++) + *(redundant + i) = 0xFF; +} + +/* ----- Set_D_LogBlockAddr() ------------------------------------------- */ +void Set_D_LogBlockAddr(BYTE *redundant) +{ + WORD 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) = (BYTE)(addr / 0x0100); + *(redundant + REDT_ADDR1L) = *(redundant + REDT_ADDR2L) = (BYTE)addr; +} + +/*----- Set_D_FailBlock() ---------------------------------------------- */ +void Set_D_FailBlock(BYTE *redundant) +{ + char i; + for (i = 0; i < REDTSIZE; i++) + *redundant++ = (BYTE)((i == REDT_BLOCK) ? 0xF0 : 0xFF); +} + +/* ----- Set_D_DataStaus() ---------------------------------------------- */ +void Set_D_DataStaus(BYTE *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, BYTE *buf, BYTE *redundant) +{ + BYTE zone, sector; + WORD 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, BYTE *buf, BYTE *redundant) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + WORD addr; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock; + addr = addr*(WORD)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] = (BYTE)addr; + bcb->CDB[3] = (BYTE)(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] = (BYTE)addr; + bcb->CDB[3] = (BYTE)(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, WORD count, BYTE *buf, BYTE *redundant) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + WORD addr; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock; + addr = addr*(WORD)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] = (BYTE)addr; + bcb->CDB[3] = (BYTE)(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] = (BYTE)addr; + bcb->CDB[3] = (BYTE)(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, WORD count, BYTE *buf, BYTE *redundant) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + WORD ReadAddr, WriteAddr; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + ReadAddr = (WORD)Media.Zone*Ssfdc.MaxBlocks + ReadBlock; + ReadAddr = ReadAddr*(WORD)Ssfdc.MaxSectors; + WriteAddr = (WORD)Media.Zone*Ssfdc.MaxBlocks + WriteBlock; + WriteAddr = WriteAddr*(WORD)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] = (BYTE)WriteAddr; + bcb->CDB[6] = (BYTE)(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] = (BYTE)ReadAddr; + bcb->CDB[3] = (BYTE)(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, BYTE *buf, BYTE *redundant) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + WORD addr; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + + addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock; + addr = addr*(WORD)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] = (BYTE)addr; + bcb->CDB[6] = (BYTE)(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; + WORD addr; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock; + addr = addr*(WORD)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] = (BYTE)addr; + bcb->CDB[6] = (BYTE)(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, BYTE *redundant) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + WORD addr; + BYTE *buf; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock; + addr = addr*(WORD)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] = (BYTE)addr; + bcb->CDB[3] = (BYTE)(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, BYTE *redundant) +{ + struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; + int result; + WORD addr; + + result = ENE_LoadBinCode(us, SM_RW_PATTERN); + if (result != USB_STOR_XFER_GOOD) { + printk("Load SM RW Code Fail !!\n"); + return USB_STOR_TRANSPORT_ERROR; + } + + addr = (WORD)Media.Zone*Ssfdc.MaxBlocks + Media.PhyBlock; + addr = addr*(WORD)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] = (BYTE)addr; + bcb->CDB[6] = (BYTE)(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(BYTE 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() --------------------------------------------- */ +BYTE _Check_D_DevCode(BYTE 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(BYTE *redundant) +{ + return SMSUCCESS; +} + +/* ----- Check_D_Correct() ---------------------------------------------- */ +int Check_D_Correct(BYTE *buf, BYTE *redundant) +{ + return SMSUCCESS; +} + +/* ----- Check_D_CISdata() ---------------------------------------------- */ +int Check_D_CISdata(BYTE *buf, BYTE *redundant) +{ + BYTE 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(BYTE *redundant) +{ + /* Driver ECC Check */ + return; +} + + diff --git a/drivers/staging/keucr/smscsi.c b/drivers/staging/keucr/smscsi.c new file mode 100644 index 00000000..58b55557 --- /dev/null +++ b/drivers/staging/keucr/smscsi.c @@ -0,0 +1,188 @@ +#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" + +int SM_SCSI_Test_Unit_Ready(struct us_data *us, struct scsi_cmnd *srb); +int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb); +int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb); +int SM_SCSI_Start_Stop(struct us_data *us, struct scsi_cmnd *srb); +int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb); +int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb); +int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb); + +extern PBYTE SMHostAddr; +extern DWORD ErrXDCode; + +/* ----- 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() -------------------------------------------------- */ +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() -------------------------------------------------- */ +int SM_SCSI_Inquiry(struct us_data *us, struct scsi_cmnd *srb) +{ + BYTE 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() -------------------------------------------------- */ +int SM_SCSI_Mode_Sense(struct us_data *us, struct scsi_cmnd *srb) +{ + BYTE mediaNoWP[12] = {0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00}; + BYTE 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() -------------------------------------------------- */ +int SM_SCSI_Read_Capacity(struct us_data *us, struct scsi_cmnd *srb) +{ + unsigned int offset = 0; + struct scatterlist *sg = NULL; + DWORD bl_num; + WORD bl_len; + BYTE buf[8]; + + printk("SM_SCSI_Read_Capacity\n"); + + bl_len = 0x200; + bl_num = Ssfdc.MaxLogBlocks * Ssfdc.MaxSectors * Ssfdc.MaxZones - 1; + + us->bl_num = bl_num; + printk("bl_len = %x\n", bl_len); + printk("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() -------------------------------------------------- */ +int SM_SCSI_Read(struct us_data *us, struct scsi_cmnd *srb) +{ + int result = 0; + PBYTE Cdb = srb->cmnd; + DWORD bn = ((Cdb[2] << 24) & 0xff000000) | ((Cdb[3] << 16) & 0x00ff0000) | + ((Cdb[4] << 8) & 0x0000ff00) | ((Cdb[5] << 0) & 0x000000ff); + WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff); + DWORD 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() -------------------------------------------------- */ +int SM_SCSI_Write(struct us_data *us, struct scsi_cmnd *srb) +{ + int result = 0; + PBYTE Cdb = srb->cmnd; + DWORD bn = ((Cdb[2] << 24) & 0xff000000) | ((Cdb[3] << 16) & 0x00ff0000) | + ((Cdb[4] << 8) & 0x0000ff00) | ((Cdb[5] << 0) & 0x000000ff); + WORD blen = ((Cdb[7] << 8) & 0xff00) | ((Cdb[8] << 0) & 0x00ff); + DWORD 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 00000000..1a8837df --- /dev/null +++ b/drivers/staging/keucr/transport.c @@ -0,0 +1,823 @@ +#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_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(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(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) +{ + BYTE *buf = srb->sense_buffer; + BYTE 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(scsi_get_resid(srb), + (int) 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 00000000..2a11a983 --- /dev/null +++ b/drivers/staging/keucr/transport.h @@ -0,0 +1,74 @@ +#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_print_cmd(struct scsi_cmnd *); +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*, BYTE, void*, int); +extern int ENE_LoadBinCode(struct us_data*, BYTE); +extern int ENE_Read_BYTE(struct us_data*, WORD 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 00000000..f656f8ae --- /dev/null +++ b/drivers/staging/keucr/usb.c @@ -0,0 +1,636 @@ +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/freezer.h> +#include <linux/module.h> +#include <linux/init.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) +{ + BYTE 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 = *(PSM_STATUS)&tmp; + + return 0; +} + +static int eucr_reset_resume(struct usb_interface *iface) +{ + BYTE 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 = *(PSM_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 */ + if (us->cr) + usb_free_coherent(us->pusb_dev, sizeof(*us->cr), us->cr, us->cr_dma); + if (us->iobuf) + 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; + BYTE 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 00000000..a5f7a16c --- /dev/null +++ b/drivers/staging/keucr/usb.h @@ -0,0 +1,237 @@ +// 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 + +typedef struct _SD_STATUS { + BYTE Insert:1; + BYTE Ready:1; + BYTE MediaChange:1; + BYTE IsMMC:1; + BYTE HiCapacity:1; + BYTE HiSpeed:1; + BYTE WtP:1; + BYTE Reserved:1; +} SD_STATUS, *PSD_STATUS; + +typedef struct _MS_STATUS { + BYTE Insert:1; + BYTE Ready:1; + BYTE MediaChange:1; + BYTE IsMSPro:1; + BYTE IsMSPHG:1; + BYTE Reserved1:1; + BYTE WtP:1; + BYTE Reserved2:1; +} MS_STATUS, *PMS_STATUS; + +typedef struct _SM_STATUS { + BYTE Insert:1; + BYTE Ready:1; + BYTE MediaChange:1; + BYTE Reserved:3; + BYTE WtP:1; + BYTE IsMS:1; +} SM_STATUS, *PSM_STATUS; + +// 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 + SD_STATUS SD_Status; + MS_STATUS MS_Status; + SM_STATUS SM_Status; + + //----- SD Control Data ---------------- + //SD_REGISTER SD_Regs; + WORD SD_Block_Mult; + BYTE SD_READ_BL_LEN; + WORD SD_C_SIZE; + BYTE SD_C_SIZE_MULT; + + // SD/MMC New spec. + BYTE SD_SPEC_VER; + BYTE SD_CSD_VER; + BYTE SD20_HIGH_CAPACITY; + DWORD HC_C_SIZE; + BYTE MMC_SPEC_VER; + BYTE MMC_BusWidth; + BYTE MMC_HIGH_CAPACITY; + + //----- MS Control Data ---------------- + BOOLEAN MS_SWWP; + DWORD MSP_TotalBlock; + /* MS_LibControl MS_Lib; */ + BOOLEAN MS_IsRWPage; + WORD MS_Model; + + //----- SM Control Data ---------------- + BYTE SM_DeviceID; + BYTE SM_CardID; + + PBYTE testbuf; + BYTE BIN_FLAG; + DWORD bl_num; + int SrbStatus; + + //------Power Managerment --------------- + BOOLEAN 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 |
