summaryrefslogtreecommitdiff
path: root/drivers/staging/keucr/init.c
diff options
context:
space:
mode:
authorAl Cho <acho@novell.com>2010-09-08 07:42:32 (GMT)
committerGreg Kroah-Hartman <gregkh@suse.de>2010-09-08 09:49:39 (GMT)
commit126bb03b461c2f03f2d2a43b9a587941bf146e0e (patch)
tree3ad752751a377039901cf00db8c0e47f26b7b9f5 /drivers/staging/keucr/init.c
parent15b9e32769de7fb563360cb6a3d96e521c3734ac (diff)
downloadlinux-fsl-qoriq-126bb03b461c2f03f2d2a43b9a587941bf146e0e.tar.xz
Staging: add USB ENE card reader driver
This driver is for the ENE card reader that can be found in many different laptops. It was written by ENE, but cleaned up to work properly in the kernel tree by Novell. Signed-off-by: Al Cho <acho@novell.com> Cc: <yiyingc@ene.com.tw> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/keucr/init.c')
-rw-r--r--drivers/staging/keucr/init.c541
1 files changed, 541 insertions, 0 deletions
diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c
new file mode 100644
index 0000000..2ae129b
--- /dev/null
+++ b/drivers/staging/keucr/init.c
@@ -0,0 +1,541 @@
+#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"
+
+BYTE IsSSFDCCompliance;
+BYTE IsXDCompliance;
+extern DWORD MediaChange;
+extern int Check_D_MediaFmt(struct us_data *);
+
+//----- ENE_InitMedia() ----------------------------------------
+int ENE_InitMedia(struct us_data *us)
+{
+ int result;
+ BYTE MiscReg03 = 0;
+
+ printk("--- Initial Nedia ---\n");
+ result = ENE_Read_BYTE(us, REG_CARD_STATUS, &MiscReg03);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Read register fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ printk("MiscReg03 = %x\n", MiscReg03);
+
+ if (MiscReg03 & 0x01)
+ {
+ if (!us->SD_Status.Ready)
+ {
+ result = ENE_SDInit(us);
+ if (result != USB_STOR_XFER_GOOD)
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ }
+
+ if (MiscReg03 & 0x02)
+ {
+ if (!us->SM_Status.Ready && !us->MS_Status.Ready)
+ {
+ result = ENE_SMInit(us);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ result = ENE_MSInit(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(bcb));
+ 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_SDInit() ---------------------
+int ENE_SDInit(struct us_data *us)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ BYTE buf[0x200];
+
+ printk("transport --- ENE_SDInit\n");
+ // SD Init Part-1
+ result = ENE_LoadBinCode(us, SD_INIT1_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Load SD Init Code Part-1 Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(bcb));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF2;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, NULL, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Exection SD Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ // SD Init Part-2
+ result = ENE_LoadBinCode(us, SD_INIT2_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Load SD Init Code Part-2 Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(bcb));
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = 0x200;
+ bcb->Flags = 0x80;
+ bcb->CDB[0] = 0xF1;
+
+ result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Exection SD Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ us->SD_Status = *(PSD_STATUS)&buf[0];
+ if (us->SD_Status.Insert && us->SD_Status.Ready)
+ {
+ ENE_ReadSDReg(us, (PBYTE)&buf);
+ printk("Insert = %x\n", us->SD_Status.Insert);
+ printk("Ready = %x\n", us->SD_Status.Ready);
+ printk("IsMMC = %x\n", us->SD_Status.IsMMC);
+ printk("HiCapacity = %x\n", us->SD_Status.HiCapacity);
+ printk("HiSpeed = %x\n", us->SD_Status.HiSpeed);
+ printk("WtP = %x\n", us->SD_Status.WtP);
+ }
+ else
+ {
+ printk("SD Card Not Ready --- %x\n", buf[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+//----- ENE_MSInit() ----------------------------------------
+int ENE_MSInit(struct us_data *us)
+{
+ struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
+ int result;
+ BYTE buf[0x200];
+ WORD MSP_BlockSize, MSP_UserAreaBlocks;
+
+
+ printk("transport --- ENE_MSInit\n");
+ result = ENE_LoadBinCode(us, MS_INIT_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Load MS Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(bcb));
+ 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("Exection MS Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ us->MS_Status = *(PMS_STATUS)&buf[0];
+
+ if (us->MS_Status.Insert && us->MS_Status.Ready)
+ {
+ printk("Insert = %x\n", us->MS_Status.Insert);
+ printk("Ready = %x\n", us->MS_Status.Ready);
+ printk("IsMSPro = %x\n", us->MS_Status.IsMSPro);
+ printk("IsMSPHG = %x\n", us->MS_Status.IsMSPHG);
+ printk("WtP = %x\n", us->MS_Status.WtP);
+ if (us->MS_Status.IsMSPro)
+ {
+ MSP_BlockSize = (buf[6] <<8) | buf[7];
+ MSP_UserAreaBlocks = (buf[10]<<8) | buf[11];
+ us->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
+ }
+ else
+ MS_CardInit(us);
+ printk("MS Init Code OK !!\n");
+ }
+ else
+ {
+ printk("MS Card Not Ready --- %x\n", buf[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+//----- 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("transport --- ENE_SMInit\n");
+
+ result = ENE_LoadBinCode(us, SM_INIT_PATTERN);
+ if (result != USB_STOR_XFER_GOOD)
+ {
+ printk("Load SM Init Code Fail !!\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ memset(bcb, 0, sizeof(bcb));
+ 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("Exection 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("Insert = %x\n", us->SM_Status.Insert);
+ printk("Ready = %x\n", us->SM_Status.Ready);
+ printk("WtP = %x\n", us->SM_Status.WtP);
+ printk("DeviceID = %x\n", us->SM_DeviceID);
+ printk("CardID = %x\n", us->SM_CardID);
+ MediaChange = 1;
+ Check_D_MediaFmt(us);
+ }
+ else
+ {
+ printk("SM Card Not Ready --- %x\n", buf[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+//----- ENE_ReadSDReg() ----------------------------------------------
+int ENE_ReadSDReg(struct us_data *us, u8 *RdBuf)
+{
+ WORD tmpreg;
+ DWORD reg4b;
+
+ //printk("transport --- ENE_ReadSDReg\n");
+ reg4b = *(PDWORD)&RdBuf[0x18];
+ us->SD_READ_BL_LEN = (BYTE)((reg4b >> 8) & 0x0f);
+
+ tmpreg = (WORD) reg4b;
+ reg4b = *(PDWORD)(&RdBuf[0x14]);
+ if (us->SD_Status.HiCapacity && !us->SD_Status.IsMMC)
+ us->HC_C_SIZE = (reg4b >> 8) & 0x3fffff;
+
+ us->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (WORD)(reg4b >> 22);
+ us->SD_C_SIZE_MULT = (BYTE)(reg4b >> 7) & 0x07;
+ if (us->SD_Status.HiCapacity && us->SD_Status.IsMMC)
+ us->HC_C_SIZE = *(PDWORD)(&RdBuf[0x100]);
+
+ if (us->SD_READ_BL_LEN > SD_BLOCK_LEN)
+ {
+ us->SD_Block_Mult = 1 << (us->SD_READ_BL_LEN - SD_BLOCK_LEN); us->SD_READ_BL_LEN = SD_BLOCK_LEN;
+ }
+ else
+ { us->SD_Block_Mult = 1;
+ }
+ 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("transport --- ENE_LoadBinCode\n");
+ if (us->BIN_FLAG == flag)
+ return USB_STOR_TRANSPORT_GOOD;
+
+ buf = kmalloc(0x800, GFP_KERNEL);
+ switch ( flag )
+ {
+ // For SD
+ case SD_INIT1_PATTERN:
+ printk("SD_INIT1_PATTERN\n");
+ memcpy(buf, SD_Init1, 0x800);
+ break;
+ case SD_INIT2_PATTERN:
+ printk("SD_INIT2_PATTERN\n");
+ memcpy(buf, SD_Init2, 0x800);
+ break;
+ case SD_RW_PATTERN:
+ printk("SD_RW_PATTERN\n");
+ memcpy(buf, SD_Rdwr, 0x800);
+ break;
+ // For MS
+ case MS_INIT_PATTERN:
+ printk("MS_INIT_PATTERN\n");
+ memcpy(buf, MS_Init, 0x800);
+ break;
+ case MSP_RW_PATTERN:
+ printk("MSP_RW_PATTERN\n");
+ memcpy(buf, MSP_Rdwr, 0x800);
+ break;
+ case MS_RW_PATTERN:
+ printk("MS_RW_PATTERN\n");
+ memcpy(buf, MS_Rdwr, 0x800);
+ break;
+ // For SS
+ case SM_INIT_PATTERN:
+ printk("SM_INIT_PATTERN\n");
+ memcpy(buf, SM_Init, 0x800);
+ break;
+ case SM_RW_PATTERN:
+ printk("SM_RW_PATTERN\n");
+ memcpy(buf, SM_Rdwr, 0x800);
+ break;
+ }
+
+ memset(bcb, 0, sizeof(bcb));
+ 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("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("send cmd to out endpoint fail ---\n");
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ if (buf)
+ {
+ unsigned int pipe = fDir == FDIR_READ ? us->recv_bulk_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("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("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("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);
+ 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("transport --- ENE_Read_Data\n");
+ // set up the command wrapper
+ memset(bcb, 0, sizeof(bcb));
+ 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(bcb));
+ 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("scsi cmd %X --- SCSIOP_TEST_UNIT_READY\n", cmd);
+ break;
+ case INQUIRY:
+ printk("scsi cmd %X --- SCSIOP_INQUIRY\n", cmd);
+ break;
+ case MODE_SENSE:
+ printk("scsi cmd %X --- SCSIOP_MODE_SENSE\n", cmd);
+ break;
+ case START_STOP:
+ printk("scsi cmd %X --- SCSIOP_START_STOP\n", cmd);
+ break;
+ case READ_CAPACITY:
+ printk("scsi cmd %X --- SCSIOP_READ_CAPACITY\n", cmd);
+ break;
+ case READ_10:
+ //printk("scsi cmd %X --- SCSIOP_READ, bn = %X, blen = %X\n", cmd, bn, blen);
+ break;
+ case WRITE_10:
+ //printk("scsi cmd %X --- SCSIOP_WRITE, bn = %X, blen = %X\n", cmd, bn, blen);
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ printk("scsi cmd %X --- SCSIOP_ALLOW_MEDIUM_REMOVAL\n", cmd);
+ break;
+ default:
+ printk("scsi cmd %X --- Other cmd\n", cmd);
+ break;
+ }
+ bn = 0;
+ blen = 0;
+}
+
+