xref: /openbmc/linux/drivers/usb/storage/ene_ub6250.c (revision 41e568d1)
141e568d1Shuajun li /*
241e568d1Shuajun li  *
341e568d1Shuajun li  * This program is free software; you can redistribute it and/or modify it
441e568d1Shuajun li  * under the terms of the GNU General Public License as published by the
541e568d1Shuajun li  * Free Software Foundation; either version 2, or (at your option) any
641e568d1Shuajun li  * later version.
741e568d1Shuajun li  *
841e568d1Shuajun li  * This program is distributed in the hope that it will be useful, but
941e568d1Shuajun li  * WITHOUT ANY WARRANTY; without even the implied warranty of
1041e568d1Shuajun li  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1141e568d1Shuajun li  * General Public License for more details.
1241e568d1Shuajun li  *
1341e568d1Shuajun li  * You should have received a copy of the GNU General Public License along
1441e568d1Shuajun li  * with this program; if not, write to the Free Software Foundation, Inc.,
1541e568d1Shuajun li  * 675 Mass Ave, Cambridge, MA 02139, USA.
1641e568d1Shuajun li  */
1741e568d1Shuajun li #include <linux/jiffies.h>
1841e568d1Shuajun li #include <linux/errno.h>
1941e568d1Shuajun li #include <linux/module.h>
2041e568d1Shuajun li #include <linux/slab.h>
2141e568d1Shuajun li 
2241e568d1Shuajun li #include <scsi/scsi.h>
2341e568d1Shuajun li #include <scsi/scsi_cmnd.h>
2441e568d1Shuajun li 
2541e568d1Shuajun li #include <linux/firmware.h>
2641e568d1Shuajun li 
2741e568d1Shuajun li #include "usb.h"
2841e568d1Shuajun li #include "transport.h"
2941e568d1Shuajun li #include "protocol.h"
3041e568d1Shuajun li #include "debug.h"
3141e568d1Shuajun li 
3241e568d1Shuajun li MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
3341e568d1Shuajun li MODULE_LICENSE("GPL");
3441e568d1Shuajun li 
3541e568d1Shuajun li 
3641e568d1Shuajun li /*
3741e568d1Shuajun li  * The table of devices
3841e568d1Shuajun li  */
3941e568d1Shuajun li #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
4041e568d1Shuajun li 		    vendorName, productName, useProtocol, useTransport, \
4141e568d1Shuajun li 		    initFunction, flags) \
4241e568d1Shuajun li { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
4341e568d1Shuajun li 	.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
4441e568d1Shuajun li 
4541e568d1Shuajun li struct usb_device_id ene_ub6250_usb_ids[] = {
4641e568d1Shuajun li #	include "unusual_ene_ub6250.h"
4741e568d1Shuajun li 	{ }		/* Terminating entry */
4841e568d1Shuajun li };
4941e568d1Shuajun li MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids);
5041e568d1Shuajun li 
5141e568d1Shuajun li #undef UNUSUAL_DEV
5241e568d1Shuajun li 
5341e568d1Shuajun li /*
5441e568d1Shuajun li  * The flags table
5541e568d1Shuajun li  */
5641e568d1Shuajun li #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
5741e568d1Shuajun li 		    vendor_name, product_name, use_protocol, use_transport, \
5841e568d1Shuajun li 		    init_function, Flags) \
5941e568d1Shuajun li { \
6041e568d1Shuajun li 	.vendorName = vendor_name,	\
6141e568d1Shuajun li 	.productName = product_name,	\
6241e568d1Shuajun li 	.useProtocol = use_protocol,	\
6341e568d1Shuajun li 	.useTransport = use_transport,	\
6441e568d1Shuajun li 	.initFunction = init_function,	\
6541e568d1Shuajun li }
6641e568d1Shuajun li 
6741e568d1Shuajun li static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = {
6841e568d1Shuajun li #	include "unusual_ene_ub6250.h"
6941e568d1Shuajun li 	{ }		/* Terminating entry */
7041e568d1Shuajun li };
7141e568d1Shuajun li 
7241e568d1Shuajun li #undef UNUSUAL_DEV
7341e568d1Shuajun li 
7441e568d1Shuajun li 
7541e568d1Shuajun li 
7641e568d1Shuajun li /* ENE bin code len */
7741e568d1Shuajun li #define ENE_BIN_CODE_LEN    0x800
7841e568d1Shuajun li /* EnE HW Register */
7941e568d1Shuajun li #define REG_CARD_STATUS     0xFF83
8041e568d1Shuajun li #define REG_HW_TRAP1        0xFF89
8141e568d1Shuajun li 
8241e568d1Shuajun li /* SRB Status */
8341e568d1Shuajun li #define SS_SUCCESS                  0x00      /* No Sense */
8441e568d1Shuajun li #define SS_NOT_READY                0x02
8541e568d1Shuajun li #define SS_MEDIUM_ERR               0x03
8641e568d1Shuajun li #define SS_HW_ERR                   0x04
8741e568d1Shuajun li #define SS_ILLEGAL_REQUEST          0x05
8841e568d1Shuajun li #define SS_UNIT_ATTENTION           0x06
8941e568d1Shuajun li 
9041e568d1Shuajun li /* ENE Load FW Pattern */
9141e568d1Shuajun li #define SD_INIT1_PATTERN   1
9241e568d1Shuajun li #define SD_INIT2_PATTERN   2
9341e568d1Shuajun li #define SD_RW_PATTERN      3
9441e568d1Shuajun li #define MS_INIT_PATTERN    4
9541e568d1Shuajun li #define MSP_RW_PATTERN     5
9641e568d1Shuajun li #define MS_RW_PATTERN      6
9741e568d1Shuajun li #define SM_INIT_PATTERN    7
9841e568d1Shuajun li #define SM_RW_PATTERN      8
9941e568d1Shuajun li 
10041e568d1Shuajun li #define FDIR_WRITE         0
10141e568d1Shuajun li #define FDIR_READ          1
10241e568d1Shuajun li 
10341e568d1Shuajun li 
10441e568d1Shuajun li struct SD_STATUS {
10541e568d1Shuajun li 	u8    Insert:1;
10641e568d1Shuajun li 	u8    Ready:1;
10741e568d1Shuajun li 	u8    MediaChange:1;
10841e568d1Shuajun li 	u8    IsMMC:1;
10941e568d1Shuajun li 	u8    HiCapacity:1;
11041e568d1Shuajun li 	u8    HiSpeed:1;
11141e568d1Shuajun li 	u8    WtP:1;
11241e568d1Shuajun li 	u8    Reserved:1;
11341e568d1Shuajun li };
11441e568d1Shuajun li 
11541e568d1Shuajun li struct MS_STATUS {
11641e568d1Shuajun li 	u8    Insert:1;
11741e568d1Shuajun li 	u8    Ready:1;
11841e568d1Shuajun li 	u8    MediaChange:1;
11941e568d1Shuajun li 	u8    IsMSPro:1;
12041e568d1Shuajun li 	u8    IsMSPHG:1;
12141e568d1Shuajun li 	u8    Reserved1:1;
12241e568d1Shuajun li 	u8    WtP:1;
12341e568d1Shuajun li 	u8    Reserved2:1;
12441e568d1Shuajun li };
12541e568d1Shuajun li 
12641e568d1Shuajun li struct SM_STATUS {
12741e568d1Shuajun li 	u8    Insert:1;
12841e568d1Shuajun li 	u8    Ready:1;
12941e568d1Shuajun li 	u8    MediaChange:1;
13041e568d1Shuajun li 	u8    Reserved:3;
13141e568d1Shuajun li 	u8    WtP:1;
13241e568d1Shuajun li 	u8    IsMS:1;
13341e568d1Shuajun li };
13441e568d1Shuajun li 
13541e568d1Shuajun li 
13641e568d1Shuajun li /* SD Block Length */
13741e568d1Shuajun li /* 2^9 = 512 Bytes, The HW maximum read/write data length */
13841e568d1Shuajun li #define SD_BLOCK_LEN  9
13941e568d1Shuajun li 
14041e568d1Shuajun li struct ene_ub6250_info {
14141e568d1Shuajun li 	/* for 6250 code */
14241e568d1Shuajun li 	struct SD_STATUS	SD_Status;
14341e568d1Shuajun li 	struct MS_STATUS	MS_Status;
14441e568d1Shuajun li 	struct SM_STATUS	SM_Status;
14541e568d1Shuajun li 
14641e568d1Shuajun li 	/* ----- SD Control Data ---------------- */
14741e568d1Shuajun li 	/*SD_REGISTER SD_Regs; */
14841e568d1Shuajun li 	u16		SD_Block_Mult;
14941e568d1Shuajun li 	u8		SD_READ_BL_LEN;
15041e568d1Shuajun li 	u16		SD_C_SIZE;
15141e568d1Shuajun li 	u8		SD_C_SIZE_MULT;
15241e568d1Shuajun li 
15341e568d1Shuajun li 	/* SD/MMC New spec. */
15441e568d1Shuajun li 	u8		SD_SPEC_VER;
15541e568d1Shuajun li 	u8		SD_CSD_VER;
15641e568d1Shuajun li 	u8		SD20_HIGH_CAPACITY;
15741e568d1Shuajun li 	u32		HC_C_SIZE;
15841e568d1Shuajun li 	u8		MMC_SPEC_VER;
15941e568d1Shuajun li 	u8		MMC_BusWidth;
16041e568d1Shuajun li 	u8		MMC_HIGH_CAPACITY;
16141e568d1Shuajun li 
16241e568d1Shuajun li 	/*----- MS Control Data ---------------- */
16341e568d1Shuajun li 	bool		MS_SWWP;
16441e568d1Shuajun li 	u32		MSP_TotalBlock;
16541e568d1Shuajun li 	/*MS_LibControl       MS_Lib;*/
16641e568d1Shuajun li 	bool		MS_IsRWPage;
16741e568d1Shuajun li 	u16		MS_Model;
16841e568d1Shuajun li 
16941e568d1Shuajun li 	/*----- SM Control Data ---------------- */
17041e568d1Shuajun li 	u8		SM_DeviceID;
17141e568d1Shuajun li 	u8		SM_CardID;
17241e568d1Shuajun li 
17341e568d1Shuajun li 	unsigned char	*testbuf;
17441e568d1Shuajun li 	u8		BIN_FLAG;
17541e568d1Shuajun li 	u32		bl_num;
17641e568d1Shuajun li 	int		SrbStatus;
17741e568d1Shuajun li 
17841e568d1Shuajun li 	/*------Power Managerment ---------------*/
17941e568d1Shuajun li 	bool		Power_IsResum;
18041e568d1Shuajun li };
18141e568d1Shuajun li 
18241e568d1Shuajun li static int ene_sd_init(struct us_data *us);
18341e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag);
18441e568d1Shuajun li 
18541e568d1Shuajun li static void ene_ub6250_info_destructor(void *extra)
18641e568d1Shuajun li {
18741e568d1Shuajun li 	if (!extra)
18841e568d1Shuajun li 		return;
18941e568d1Shuajun li }
19041e568d1Shuajun li 
19141e568d1Shuajun li static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
19241e568d1Shuajun li {
19341e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
19441e568d1Shuajun li 	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
19541e568d1Shuajun li 
19641e568d1Shuajun li 	int result;
19741e568d1Shuajun li 	unsigned int residue;
19841e568d1Shuajun li 	unsigned int cswlen = 0, partial = 0;
19941e568d1Shuajun li 	unsigned int transfer_length = bcb->DataTransferLength;
20041e568d1Shuajun li 
20141e568d1Shuajun li 	/* US_DEBUGP("transport --- ene_send_scsi_cmd\n"); */
20241e568d1Shuajun li 	/* send cmd to out endpoint */
20341e568d1Shuajun li 	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
20441e568d1Shuajun li 					    bcb, US_BULK_CB_WRAP_LEN, NULL);
20541e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
20641e568d1Shuajun li 		US_DEBUGP("send cmd to out endpoint fail ---\n");
20741e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
20841e568d1Shuajun li 	}
20941e568d1Shuajun li 
21041e568d1Shuajun li 	if (buf) {
21141e568d1Shuajun li 		unsigned int pipe = fDir;
21241e568d1Shuajun li 
21341e568d1Shuajun li 		if (fDir  == FDIR_READ)
21441e568d1Shuajun li 			pipe = us->recv_bulk_pipe;
21541e568d1Shuajun li 		else
21641e568d1Shuajun li 			pipe = us->send_bulk_pipe;
21741e568d1Shuajun li 
21841e568d1Shuajun li 		/* Bulk */
21941e568d1Shuajun li 		if (use_sg) {
22041e568d1Shuajun li 			result = usb_stor_bulk_srb(us, pipe, us->srb);
22141e568d1Shuajun li 		} else {
22241e568d1Shuajun li 			result = usb_stor_bulk_transfer_sg(us, pipe, buf,
22341e568d1Shuajun li 						transfer_length, 0, &partial);
22441e568d1Shuajun li 		}
22541e568d1Shuajun li 		if (result != USB_STOR_XFER_GOOD) {
22641e568d1Shuajun li 			US_DEBUGP("data transfer fail ---\n");
22741e568d1Shuajun li 			return USB_STOR_TRANSPORT_ERROR;
22841e568d1Shuajun li 		}
22941e568d1Shuajun li 	}
23041e568d1Shuajun li 
23141e568d1Shuajun li 	/* Get CSW for device status */
23241e568d1Shuajun li 	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
23341e568d1Shuajun li 					    US_BULK_CS_WRAP_LEN, &cswlen);
23441e568d1Shuajun li 
23541e568d1Shuajun li 	if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
23641e568d1Shuajun li 		US_DEBUGP("Received 0-length CSW; retrying...\n");
23741e568d1Shuajun li 		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
23841e568d1Shuajun li 					    bcs, US_BULK_CS_WRAP_LEN, &cswlen);
23941e568d1Shuajun li 	}
24041e568d1Shuajun li 
24141e568d1Shuajun li 	if (result == USB_STOR_XFER_STALLED) {
24241e568d1Shuajun li 		/* get the status again */
24341e568d1Shuajun li 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
24441e568d1Shuajun li 		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
24541e568d1Shuajun li 						bcs, US_BULK_CS_WRAP_LEN, NULL);
24641e568d1Shuajun li 	}
24741e568d1Shuajun li 
24841e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD)
24941e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
25041e568d1Shuajun li 
25141e568d1Shuajun li 	/* check bulk status */
25241e568d1Shuajun li 	residue = le32_to_cpu(bcs->Residue);
25341e568d1Shuajun li 
25441e568d1Shuajun li 	/* try to compute the actual residue, based on how much data
25541e568d1Shuajun li 	 * was really transferred and what the device tells us */
25641e568d1Shuajun li 	if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
25741e568d1Shuajun li 		residue = min(residue, transfer_length);
25841e568d1Shuajun li 		if (us->srb != NULL)
25941e568d1Shuajun li 			scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
26041e568d1Shuajun li 								(int)residue));
26141e568d1Shuajun li 	}
26241e568d1Shuajun li 
26341e568d1Shuajun li 	if (bcs->Status != US_BULK_STAT_OK)
26441e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
26541e568d1Shuajun li 
26641e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
26741e568d1Shuajun li }
26841e568d1Shuajun li 
26941e568d1Shuajun li static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
27041e568d1Shuajun li {
27141e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
27241e568d1Shuajun li 
27341e568d1Shuajun li 	if (info->SD_Status.Insert && info->SD_Status.Ready)
27441e568d1Shuajun li 		return USB_STOR_TRANSPORT_GOOD;
27541e568d1Shuajun li 	else {
27641e568d1Shuajun li 		ene_sd_init(us);
27741e568d1Shuajun li 		return USB_STOR_TRANSPORT_GOOD;
27841e568d1Shuajun li 	}
27941e568d1Shuajun li 
28041e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
28141e568d1Shuajun li }
28241e568d1Shuajun li 
28341e568d1Shuajun li static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
28441e568d1Shuajun li {
28541e568d1Shuajun li 	unsigned char data_ptr[36] = {
28641e568d1Shuajun li 		0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
28741e568d1Shuajun li 		0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
28841e568d1Shuajun li 		0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
28941e568d1Shuajun li 		0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 };
29041e568d1Shuajun li 
29141e568d1Shuajun li 	usb_stor_set_xfer_buf(data_ptr, 36, srb);
29241e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
29341e568d1Shuajun li }
29441e568d1Shuajun li 
29541e568d1Shuajun li static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
29641e568d1Shuajun li {
29741e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
29841e568d1Shuajun li 	unsigned char mediaNoWP[12] = {
29941e568d1Shuajun li 		0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
30041e568d1Shuajun li 		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
30141e568d1Shuajun li 	unsigned char mediaWP[12]   = {
30241e568d1Shuajun li 		0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
30341e568d1Shuajun li 		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
30441e568d1Shuajun li 
30541e568d1Shuajun li 	if (info->SD_Status.WtP)
30641e568d1Shuajun li 		usb_stor_set_xfer_buf(mediaWP, 12, srb);
30741e568d1Shuajun li 	else
30841e568d1Shuajun li 		usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
30941e568d1Shuajun li 
31041e568d1Shuajun li 
31141e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
31241e568d1Shuajun li }
31341e568d1Shuajun li 
31441e568d1Shuajun li static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
31541e568d1Shuajun li {
31641e568d1Shuajun li 	u32   bl_num;
31741e568d1Shuajun li 	u16    bl_len;
31841e568d1Shuajun li 	unsigned int offset = 0;
31941e568d1Shuajun li 	unsigned char    buf[8];
32041e568d1Shuajun li 	struct scatterlist *sg = NULL;
32141e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
32241e568d1Shuajun li 
32341e568d1Shuajun li 	US_DEBUGP("sd_scsi_read_capacity\n");
32441e568d1Shuajun li 	if (info->SD_Status.HiCapacity) {
32541e568d1Shuajun li 		bl_len = 0x200;
32641e568d1Shuajun li 		if (info->SD_Status.IsMMC)
32741e568d1Shuajun li 			bl_num = info->HC_C_SIZE-1;
32841e568d1Shuajun li 		else
32941e568d1Shuajun li 			bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
33041e568d1Shuajun li 	} else {
33141e568d1Shuajun li 		bl_len = 1<<(info->SD_READ_BL_LEN);
33241e568d1Shuajun li 		bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
33341e568d1Shuajun li 				* (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
33441e568d1Shuajun li 	}
33541e568d1Shuajun li 	info->bl_num = bl_num;
33641e568d1Shuajun li 	US_DEBUGP("bl_len = %x\n", bl_len);
33741e568d1Shuajun li 	US_DEBUGP("bl_num = %x\n", bl_num);
33841e568d1Shuajun li 
33941e568d1Shuajun li 	/*srb->request_bufflen = 8; */
34041e568d1Shuajun li 	buf[0] = (bl_num >> 24) & 0xff;
34141e568d1Shuajun li 	buf[1] = (bl_num >> 16) & 0xff;
34241e568d1Shuajun li 	buf[2] = (bl_num >> 8) & 0xff;
34341e568d1Shuajun li 	buf[3] = (bl_num >> 0) & 0xff;
34441e568d1Shuajun li 	buf[4] = (bl_len >> 24) & 0xff;
34541e568d1Shuajun li 	buf[5] = (bl_len >> 16) & 0xff;
34641e568d1Shuajun li 	buf[6] = (bl_len >> 8) & 0xff;
34741e568d1Shuajun li 	buf[7] = (bl_len >> 0) & 0xff;
34841e568d1Shuajun li 
34941e568d1Shuajun li 	usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
35041e568d1Shuajun li 
35141e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
35241e568d1Shuajun li }
35341e568d1Shuajun li 
35441e568d1Shuajun li static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
35541e568d1Shuajun li {
35641e568d1Shuajun li 	int result;
35741e568d1Shuajun li 	unsigned char *cdb = srb->cmnd;
35841e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
35941e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
36041e568d1Shuajun li 
36141e568d1Shuajun li 	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
36241e568d1Shuajun li 		 ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
36341e568d1Shuajun li 	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
36441e568d1Shuajun li 	u32 bnByte = bn * 0x200;
36541e568d1Shuajun li 	u32 blenByte = blen * 0x200;
36641e568d1Shuajun li 
36741e568d1Shuajun li 	if (bn > info->bl_num)
36841e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
36941e568d1Shuajun li 
37041e568d1Shuajun li 	result = ene_load_bincode(us, SD_RW_PATTERN);
37141e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
37241e568d1Shuajun li 		US_DEBUGP("Load SD RW pattern Fail !!\n");
37341e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
37441e568d1Shuajun li 	}
37541e568d1Shuajun li 
37641e568d1Shuajun li 	if (info->SD_Status.HiCapacity)
37741e568d1Shuajun li 		bnByte = bn;
37841e568d1Shuajun li 
37941e568d1Shuajun li 	/* set up the command wrapper */
38041e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
38141e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
38241e568d1Shuajun li 	bcb->DataTransferLength = blenByte;
38341e568d1Shuajun li 	bcb->Flags  = 0x80;
38441e568d1Shuajun li 	bcb->CDB[0] = 0xF1;
38541e568d1Shuajun li 	bcb->CDB[5] = (unsigned char)(bnByte);
38641e568d1Shuajun li 	bcb->CDB[4] = (unsigned char)(bnByte>>8);
38741e568d1Shuajun li 	bcb->CDB[3] = (unsigned char)(bnByte>>16);
38841e568d1Shuajun li 	bcb->CDB[2] = (unsigned char)(bnByte>>24);
38941e568d1Shuajun li 
39041e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
39141e568d1Shuajun li 	return result;
39241e568d1Shuajun li }
39341e568d1Shuajun li 
39441e568d1Shuajun li static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
39541e568d1Shuajun li {
39641e568d1Shuajun li 	int result;
39741e568d1Shuajun li 	unsigned char *cdb = srb->cmnd;
39841e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
39941e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
40041e568d1Shuajun li 
40141e568d1Shuajun li 	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
40241e568d1Shuajun li 		 ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
40341e568d1Shuajun li 	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
40441e568d1Shuajun li 	u32 bnByte = bn * 0x200;
40541e568d1Shuajun li 	u32 blenByte = blen * 0x200;
40641e568d1Shuajun li 
40741e568d1Shuajun li 	if (bn > info->bl_num)
40841e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
40941e568d1Shuajun li 
41041e568d1Shuajun li 	result = ene_load_bincode(us, SD_RW_PATTERN);
41141e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
41241e568d1Shuajun li 		US_DEBUGP("Load SD RW pattern Fail !!\n");
41341e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
41441e568d1Shuajun li 	}
41541e568d1Shuajun li 
41641e568d1Shuajun li 	if (info->SD_Status.HiCapacity)
41741e568d1Shuajun li 		bnByte = bn;
41841e568d1Shuajun li 
41941e568d1Shuajun li 	/* set up the command wrapper */
42041e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
42141e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
42241e568d1Shuajun li 	bcb->DataTransferLength = blenByte;
42341e568d1Shuajun li 	bcb->Flags  = 0x00;
42441e568d1Shuajun li 	bcb->CDB[0] = 0xF0;
42541e568d1Shuajun li 	bcb->CDB[5] = (unsigned char)(bnByte);
42641e568d1Shuajun li 	bcb->CDB[4] = (unsigned char)(bnByte>>8);
42741e568d1Shuajun li 	bcb->CDB[3] = (unsigned char)(bnByte>>16);
42841e568d1Shuajun li 	bcb->CDB[2] = (unsigned char)(bnByte>>24);
42941e568d1Shuajun li 
43041e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
43141e568d1Shuajun li 	return result;
43241e568d1Shuajun li }
43341e568d1Shuajun li 
43441e568d1Shuajun li static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
43541e568d1Shuajun li {
43641e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
43741e568d1Shuajun li 	int result;
43841e568d1Shuajun li 
43941e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
44041e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
44141e568d1Shuajun li 	bcb->DataTransferLength	= 0x01;
44241e568d1Shuajun li 	bcb->Flags			= 0x80;
44341e568d1Shuajun li 	bcb->CDB[0]			= 0xED;
44441e568d1Shuajun li 	bcb->CDB[2]			= (unsigned char)(index>>8);
44541e568d1Shuajun li 	bcb->CDB[3]			= (unsigned char)index;
44641e568d1Shuajun li 
44741e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
44841e568d1Shuajun li 	return result;
44941e568d1Shuajun li }
45041e568d1Shuajun li 
45141e568d1Shuajun li static int ene_get_card_status(struct us_data *us, u8 *buf)
45241e568d1Shuajun li {
45341e568d1Shuajun li 	u16 tmpreg;
45441e568d1Shuajun li 	u32 reg4b;
45541e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
45641e568d1Shuajun li 
45741e568d1Shuajun li 	/*US_DEBUGP("transport --- ENE_ReadSDReg\n");*/
45841e568d1Shuajun li 	reg4b = *(u32 *)&buf[0x18];
45941e568d1Shuajun li 	info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f);
46041e568d1Shuajun li 
46141e568d1Shuajun li 	tmpreg = (u16) reg4b;
46241e568d1Shuajun li 	reg4b = *(u32 *)(&buf[0x14]);
46341e568d1Shuajun li 	if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC)
46441e568d1Shuajun li 		info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff;
46541e568d1Shuajun li 
46641e568d1Shuajun li 	info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22);
46741e568d1Shuajun li 	info->SD_C_SIZE_MULT = (u8)(reg4b >> 7)  & 0x07;
46841e568d1Shuajun li 	if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC)
46941e568d1Shuajun li 		info->HC_C_SIZE = *(u32 *)(&buf[0x100]);
47041e568d1Shuajun li 
47141e568d1Shuajun li 	if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) {
47241e568d1Shuajun li 		info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN);
47341e568d1Shuajun li 		info->SD_READ_BL_LEN = SD_BLOCK_LEN;
47441e568d1Shuajun li 	} else {
47541e568d1Shuajun li 		info->SD_Block_Mult = 1;
47641e568d1Shuajun li 	}
47741e568d1Shuajun li 
47841e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
47941e568d1Shuajun li }
48041e568d1Shuajun li 
48141e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag)
48241e568d1Shuajun li {
48341e568d1Shuajun li 	int err;
48441e568d1Shuajun li 	char *fw_name = NULL;
48541e568d1Shuajun li 	unsigned char *buf = NULL;
48641e568d1Shuajun li 	const struct firmware *sd_fw = NULL;
48741e568d1Shuajun li 	int result = USB_STOR_TRANSPORT_ERROR;
48841e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
48941e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
49041e568d1Shuajun li 
49141e568d1Shuajun li 	if (info->BIN_FLAG == flag)
49241e568d1Shuajun li 		return USB_STOR_TRANSPORT_GOOD;
49341e568d1Shuajun li 
49441e568d1Shuajun li 	buf = kmalloc(ENE_BIN_CODE_LEN, GFP_KERNEL);
49541e568d1Shuajun li 	if (buf == NULL)
49641e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
49741e568d1Shuajun li 
49841e568d1Shuajun li 	switch (flag) {
49941e568d1Shuajun li 	/* For SD */
50041e568d1Shuajun li 	case SD_INIT1_PATTERN:
50141e568d1Shuajun li 		US_DEBUGP("SD_INIT1_PATTERN\n");
50241e568d1Shuajun li 		fw_name = "ene-ub6250/sd_init1.bin";
50341e568d1Shuajun li 		break;
50441e568d1Shuajun li 	case SD_INIT2_PATTERN:
50541e568d1Shuajun li 		US_DEBUGP("SD_INIT2_PATTERN\n");
50641e568d1Shuajun li 		fw_name = "ene-ub6250/sd_init2.bin";
50741e568d1Shuajun li 		break;
50841e568d1Shuajun li 	case SD_RW_PATTERN:
50941e568d1Shuajun li 		US_DEBUGP("SD_RDWR_PATTERN\n");
51041e568d1Shuajun li 		fw_name = "ene-ub6250/sd_rdwr.bin";
51141e568d1Shuajun li 		break;
51241e568d1Shuajun li 	default:
51341e568d1Shuajun li 		US_DEBUGP("----------- Unknown PATTERN ----------\n");
51441e568d1Shuajun li 		goto nofw;
51541e568d1Shuajun li 	}
51641e568d1Shuajun li 
51741e568d1Shuajun li 	err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev);
51841e568d1Shuajun li 	if (err) {
51941e568d1Shuajun li 		US_DEBUGP("load firmware %s failed\n", fw_name);
52041e568d1Shuajun li 		goto nofw;
52141e568d1Shuajun li 	}
52241e568d1Shuajun li 	buf = kmalloc(sd_fw->size, GFP_KERNEL);
52341e568d1Shuajun li 	if (buf == NULL) {
52441e568d1Shuajun li 		US_DEBUGP("Malloc memory for fireware failed!\n");
52541e568d1Shuajun li 		goto nofw;
52641e568d1Shuajun li 	}
52741e568d1Shuajun li 	memcpy(buf, sd_fw->data, sd_fw->size);
52841e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
52941e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
53041e568d1Shuajun li 	bcb->DataTransferLength = sd_fw->size;
53141e568d1Shuajun li 	bcb->Flags = 0x00;
53241e568d1Shuajun li 	bcb->CDB[0] = 0xEF;
53341e568d1Shuajun li 
53441e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
53541e568d1Shuajun li 	info->BIN_FLAG = flag;
53641e568d1Shuajun li 	kfree(buf);
53741e568d1Shuajun li 
53841e568d1Shuajun li nofw:
53941e568d1Shuajun li 	if (sd_fw != NULL) {
54041e568d1Shuajun li 		release_firmware(sd_fw);
54141e568d1Shuajun li 		sd_fw = NULL;
54241e568d1Shuajun li 	}
54341e568d1Shuajun li 
54441e568d1Shuajun li 	return result;
54541e568d1Shuajun li }
54641e568d1Shuajun li 
54741e568d1Shuajun li static int ene_sd_init(struct us_data *us)
54841e568d1Shuajun li {
54941e568d1Shuajun li 	int result;
55041e568d1Shuajun li 	u8  buf[0x200];
55141e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
55241e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
55341e568d1Shuajun li 
55441e568d1Shuajun li 	US_DEBUGP("transport --- ENE_SDInit\n");
55541e568d1Shuajun li 	/* SD Init Part-1 */
55641e568d1Shuajun li 	result = ene_load_bincode(us, SD_INIT1_PATTERN);
55741e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
55841e568d1Shuajun li 		US_DEBUGP("Load SD Init Code Part-1 Fail !!\n");
55941e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
56041e568d1Shuajun li 	}
56141e568d1Shuajun li 
56241e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
56341e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
56441e568d1Shuajun li 	bcb->Flags = 0x80;
56541e568d1Shuajun li 	bcb->CDB[0] = 0xF2;
56641e568d1Shuajun li 
56741e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
56841e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
56941e568d1Shuajun li 		US_DEBUGP("Exection SD Init Code Fail !!\n");
57041e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
57141e568d1Shuajun li 	}
57241e568d1Shuajun li 
57341e568d1Shuajun li 	/* SD Init Part-2 */
57441e568d1Shuajun li 	result = ene_load_bincode(us, SD_INIT2_PATTERN);
57541e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
57641e568d1Shuajun li 		US_DEBUGP("Load SD Init Code Part-2 Fail !!\n");
57741e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
57841e568d1Shuajun li 	}
57941e568d1Shuajun li 
58041e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
58141e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
58241e568d1Shuajun li 	bcb->DataTransferLength = 0x200;
58341e568d1Shuajun li 	bcb->Flags              = 0x80;
58441e568d1Shuajun li 	bcb->CDB[0]             = 0xF1;
58541e568d1Shuajun li 
58641e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
58741e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
58841e568d1Shuajun li 		US_DEBUGP("Exection SD Init Code Fail !!\n");
58941e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
59041e568d1Shuajun li 	}
59141e568d1Shuajun li 
59241e568d1Shuajun li 	info->SD_Status =  *(struct SD_STATUS *)&buf[0];
59341e568d1Shuajun li 	if (info->SD_Status.Insert && info->SD_Status.Ready) {
59441e568d1Shuajun li 		ene_get_card_status(us, (unsigned char *)&buf);
59541e568d1Shuajun li 		US_DEBUGP("Insert     = %x\n", info->SD_Status.Insert);
59641e568d1Shuajun li 		US_DEBUGP("Ready      = %x\n", info->SD_Status.Ready);
59741e568d1Shuajun li 		US_DEBUGP("IsMMC      = %x\n", info->SD_Status.IsMMC);
59841e568d1Shuajun li 		US_DEBUGP("HiCapacity = %x\n", info->SD_Status.HiCapacity);
59941e568d1Shuajun li 		US_DEBUGP("HiSpeed    = %x\n", info->SD_Status.HiSpeed);
60041e568d1Shuajun li 		US_DEBUGP("WtP        = %x\n", info->SD_Status.WtP);
60141e568d1Shuajun li 	} else {
60241e568d1Shuajun li 		US_DEBUGP("SD Card Not Ready --- %x\n", buf[0]);
60341e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
60441e568d1Shuajun li 	}
60541e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
60641e568d1Shuajun li }
60741e568d1Shuajun li 
60841e568d1Shuajun li 
60941e568d1Shuajun li static int ene_init(struct us_data *us)
61041e568d1Shuajun li {
61141e568d1Shuajun li 	int result;
61241e568d1Shuajun li 	u8  misc_reg03 = 0;
61341e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
61441e568d1Shuajun li 
61541e568d1Shuajun li 	result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
61641e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD)
61741e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
61841e568d1Shuajun li 
61941e568d1Shuajun li 	if (misc_reg03 & 0x01) {
62041e568d1Shuajun li 		if (!info->SD_Status.Ready) {
62141e568d1Shuajun li 			result = ene_sd_init(us);
62241e568d1Shuajun li 			if (result != USB_STOR_XFER_GOOD)
62341e568d1Shuajun li 				return USB_STOR_TRANSPORT_ERROR;
62441e568d1Shuajun li 		}
62541e568d1Shuajun li 	}
62641e568d1Shuajun li 
62741e568d1Shuajun li 	return result;
62841e568d1Shuajun li }
62941e568d1Shuajun li 
63041e568d1Shuajun li /*----- sd_scsi_irp() ---------*/
63141e568d1Shuajun li static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
63241e568d1Shuajun li {
63341e568d1Shuajun li 	int    result;
63441e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
63541e568d1Shuajun li 
63641e568d1Shuajun li 	info->SrbStatus = SS_SUCCESS;
63741e568d1Shuajun li 	switch (srb->cmnd[0]) {
63841e568d1Shuajun li 	case TEST_UNIT_READY:
63941e568d1Shuajun li 		result = sd_scsi_test_unit_ready(us, srb);
64041e568d1Shuajun li 		break; /* 0x00 */
64141e568d1Shuajun li 	case INQUIRY:
64241e568d1Shuajun li 		result = sd_scsi_inquiry(us, srb);
64341e568d1Shuajun li 		break; /* 0x12 */
64441e568d1Shuajun li 	case MODE_SENSE:
64541e568d1Shuajun li 		result = sd_scsi_mode_sense(us, srb);
64641e568d1Shuajun li 		break; /* 0x1A */
64741e568d1Shuajun li 	/*
64841e568d1Shuajun li 	case START_STOP:
64941e568d1Shuajun li 		result = SD_SCSI_Start_Stop(us, srb);
65041e568d1Shuajun li 		break; //0x1B
65141e568d1Shuajun li 	*/
65241e568d1Shuajun li 	case READ_CAPACITY:
65341e568d1Shuajun li 		result = sd_scsi_read_capacity(us, srb);
65441e568d1Shuajun li 		break; /* 0x25 */
65541e568d1Shuajun li 	case READ_10:
65641e568d1Shuajun li 		result = sd_scsi_read(us, srb);
65741e568d1Shuajun li 		break; /* 0x28 */
65841e568d1Shuajun li 	case WRITE_10:
65941e568d1Shuajun li 		result = sd_scsi_write(us, srb);
66041e568d1Shuajun li 		break; /* 0x2A */
66141e568d1Shuajun li 	default:
66241e568d1Shuajun li 		info->SrbStatus = SS_ILLEGAL_REQUEST;
66341e568d1Shuajun li 		result = USB_STOR_TRANSPORT_FAILED;
66441e568d1Shuajun li 		break;
66541e568d1Shuajun li 	}
66641e568d1Shuajun li 	return result;
66741e568d1Shuajun li }
66841e568d1Shuajun li 
66941e568d1Shuajun li static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
67041e568d1Shuajun li {
67141e568d1Shuajun li 	int result = 0;
67241e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
67341e568d1Shuajun li 
67441e568d1Shuajun li 	/*US_DEBUG(usb_stor_show_command(srb)); */
67541e568d1Shuajun li 	scsi_set_resid(srb, 0);
67641e568d1Shuajun li 	if (unlikely(!info->SD_Status.Ready))
67741e568d1Shuajun li 		result = ene_init(us);
67841e568d1Shuajun li 	else
67941e568d1Shuajun li 		result = sd_scsi_irp(us, srb);
68041e568d1Shuajun li 
68141e568d1Shuajun li 	return 0;
68241e568d1Shuajun li }
68341e568d1Shuajun li 
68441e568d1Shuajun li 
68541e568d1Shuajun li static int ene_ub6250_probe(struct usb_interface *intf,
68641e568d1Shuajun li 			 const struct usb_device_id *id)
68741e568d1Shuajun li {
68841e568d1Shuajun li 	int result;
68941e568d1Shuajun li 	u8  misc_reg03 = 0;
69041e568d1Shuajun li 	struct us_data *us;
69141e568d1Shuajun li 
69241e568d1Shuajun li 	result = usb_stor_probe1(&us, intf, id,
69341e568d1Shuajun li 		   (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list);
69441e568d1Shuajun li 	if (result)
69541e568d1Shuajun li 		return result;
69641e568d1Shuajun li 
69741e568d1Shuajun li 	/* FIXME: where should the code alloc extra buf ? */
69841e568d1Shuajun li 	if (!us->extra) {
69941e568d1Shuajun li 		us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
70041e568d1Shuajun li 		if (!us->extra)
70141e568d1Shuajun li 			return -ENOMEM;
70241e568d1Shuajun li 		us->extra_destructor = ene_ub6250_info_destructor;
70341e568d1Shuajun li 	}
70441e568d1Shuajun li 
70541e568d1Shuajun li 	us->transport_name = "ene_ub6250";
70641e568d1Shuajun li 	us->transport = ene_transport;
70741e568d1Shuajun li 	us->max_lun = 0;
70841e568d1Shuajun li 
70941e568d1Shuajun li 	result = usb_stor_probe2(us);
71041e568d1Shuajun li 	if (result)
71141e568d1Shuajun li 		return result;
71241e568d1Shuajun li 
71341e568d1Shuajun li 	/* probe card type */
71441e568d1Shuajun li 	result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
71541e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
71641e568d1Shuajun li 		usb_stor_disconnect(intf);
71741e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
71841e568d1Shuajun li 	}
71941e568d1Shuajun li 
72041e568d1Shuajun li 	if (!(misc_reg03 & 0x01)) {
72141e568d1Shuajun li 		result = -ENODEV;
72241e568d1Shuajun li 		printk(KERN_NOTICE "ums_eneub6250: The driver only supports SD\
72341e568d1Shuajun li 		card. To use SM/MS card, please build driver/stagging/keucr\n");
72441e568d1Shuajun li 		usb_stor_disconnect(intf);
72541e568d1Shuajun li 	}
72641e568d1Shuajun li 
72741e568d1Shuajun li 	return result;
72841e568d1Shuajun li }
72941e568d1Shuajun li 
73041e568d1Shuajun li 
73141e568d1Shuajun li #ifdef CONFIG_PM
73241e568d1Shuajun li 
73341e568d1Shuajun li static int ene_ub6250_resume(struct usb_interface *iface)
73441e568d1Shuajun li {
73541e568d1Shuajun li 	u8 tmp = 0;
73641e568d1Shuajun li 	struct us_data *us = usb_get_intfdata(iface);
73741e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
73841e568d1Shuajun li 
73941e568d1Shuajun li 	mutex_lock(&us->dev_mutex);
74041e568d1Shuajun li 
74141e568d1Shuajun li 	US_DEBUGP("%s\n", __func__);
74241e568d1Shuajun li 	if (us->suspend_resume_hook)
74341e568d1Shuajun li 		(us->suspend_resume_hook)(us, US_RESUME);
74441e568d1Shuajun li 
74541e568d1Shuajun li 	mutex_unlock(&us->dev_mutex);
74641e568d1Shuajun li 
74741e568d1Shuajun li 	info->Power_IsResum = true;
74841e568d1Shuajun li 	/*info->SD_Status.Ready = 0; */
74941e568d1Shuajun li 	info->SD_Status = *(struct SD_STATUS *)&tmp;
75041e568d1Shuajun li 	info->MS_Status = *(struct MS_STATUS *)&tmp;
75141e568d1Shuajun li 	info->SM_Status = *(struct SM_STATUS *)&tmp;
75241e568d1Shuajun li 
75341e568d1Shuajun li 	return 0;
75441e568d1Shuajun li }
75541e568d1Shuajun li 
75641e568d1Shuajun li static int ene_ub6250_reset_resume(struct usb_interface *iface)
75741e568d1Shuajun li {
75841e568d1Shuajun li 	u8 tmp = 0;
75941e568d1Shuajun li 	struct us_data *us = usb_get_intfdata(iface);
76041e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
76141e568d1Shuajun li 	US_DEBUGP("%s\n", __func__);
76241e568d1Shuajun li 	/* Report the reset to the SCSI core */
76341e568d1Shuajun li 	usb_stor_reset_resume(iface);
76441e568d1Shuajun li 
76541e568d1Shuajun li 	/* FIXME: Notify the subdrivers that they need to reinitialize
76641e568d1Shuajun li 	 * the device */
76741e568d1Shuajun li 	info->Power_IsResum = true;
76841e568d1Shuajun li 	/*info->SD_Status.Ready = 0; */
76941e568d1Shuajun li 	info->SD_Status = *(struct SD_STATUS *)&tmp;
77041e568d1Shuajun li 	info->MS_Status = *(struct MS_STATUS *)&tmp;
77141e568d1Shuajun li 	info->SM_Status = *(struct SM_STATUS *)&tmp;
77241e568d1Shuajun li 
77341e568d1Shuajun li 	return 0;
77441e568d1Shuajun li }
77541e568d1Shuajun li 
77641e568d1Shuajun li #else
77741e568d1Shuajun li 
77841e568d1Shuajun li #define ene_ub6250_resume		NULL
77941e568d1Shuajun li #define ene_ub6250_reset_resume		NULL
78041e568d1Shuajun li 
78141e568d1Shuajun li #endif
78241e568d1Shuajun li 
78341e568d1Shuajun li static struct usb_driver ene_ub6250_driver = {
78441e568d1Shuajun li 	.name =		"ums_eneub6250",
78541e568d1Shuajun li 	.probe =	ene_ub6250_probe,
78641e568d1Shuajun li 	.disconnect =	usb_stor_disconnect,
78741e568d1Shuajun li 	.suspend =	usb_stor_suspend,
78841e568d1Shuajun li 	.resume =	ene_ub6250_resume,
78941e568d1Shuajun li 	.reset_resume =	ene_ub6250_reset_resume,
79041e568d1Shuajun li 	.pre_reset =	usb_stor_pre_reset,
79141e568d1Shuajun li 	.post_reset =	usb_stor_post_reset,
79241e568d1Shuajun li 	.id_table =	ene_ub6250_usb_ids,
79341e568d1Shuajun li 	.soft_unbind =	1,
79441e568d1Shuajun li };
79541e568d1Shuajun li 
79641e568d1Shuajun li static int __init ene_ub6250_init(void)
79741e568d1Shuajun li {
79841e568d1Shuajun li 	return usb_register(&ene_ub6250_driver);
79941e568d1Shuajun li }
80041e568d1Shuajun li 
80141e568d1Shuajun li static void __exit ene_ub6250_exit(void)
80241e568d1Shuajun li {
80341e568d1Shuajun li 	usb_deregister(&ene_ub6250_driver);
80441e568d1Shuajun li }
80541e568d1Shuajun li 
80641e568d1Shuajun li module_init(ene_ub6250_init);
80741e568d1Shuajun li module_exit(ene_ub6250_exit);
808