summaryrefslogtreecommitdiffstats
path: root/target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c
diff options
context:
space:
mode:
authorRoman Yeryomin <roman@advem.lv>2013-05-17 20:40:24 +0300
committerRoman Yeryomin <roman@advem.lv>2013-05-26 00:48:34 +0300
commit7e810011201bf926cba09ec07424893e4cd8ce67 (patch)
tree202fc7a42607e366848ca59c7a61a8f9fa2712ca /target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c
parenta45894b5a0f65585440d98bf71ef3e919c84cb5f (diff)
Move to rsdk 3.2.4. Compiles cleanly.
Signed-off-by: Roman Yeryomin <roman@advem.lv>
Diffstat (limited to 'target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c')
-rw-r--r--target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c709
1 files changed, 709 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c b/target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c
new file mode 100644
index 000000000..7b65a573f
--- /dev/null
+++ b/target/linux/realtek/files/drivers/usb/misc/rts51xx/ms_mg.c
@@ -0,0 +1,709 @@
+/* Driver for Realtek RTS51xx USB card reader
+ *
+ * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http:
+ *
+ * Author:
+ * wwang (wei_wang@realsil.com.cn)
+ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ */
+
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "debug.h"
+#include "trace.h"
+#include "rts51x.h"
+#include "rts51x_transport.h"
+#include "rts51x_scsi.h"
+#include "rts51x_card.h"
+#include "ms.h"
+
+#ifdef SUPPORT_MAGIC_GATE
+
+int ms_switch_clock(struct rts51x_chip *chip);
+int ms_write_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len);
+int ms_read_bytes(struct rts51x_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len);
+int ms_set_rw_reg_addr(struct rts51x_chip *chip,
+ u8 read_start, u8 read_cnt, u8 write_start, u8 write_cnt);
+int ms_transfer_data(struct rts51x_chip *chip, u8 trans_mode, u8 tpc, u16 sec_cnt,
+ u8 cfg, int mode_2k, int use_sg, void *buf, int buf_len);
+
+
+int mg_check_int_error(struct rts51x_chip *chip)
+{
+ u8 value;
+
+ rts51x_read_register(chip,MS_TRANS_CFG,&value);
+ if(value&(INT_ERR|INT_CMDNK))
+ {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static int mg_send_ex_cmd(struct rts51x_chip *chip, u8 cmd, u8 entry_num)
+{
+ int retval, i;
+ u8 data[8];
+
+ data[0] = cmd;
+ data[1] = 0;
+ data[2] = 0;
+ data[3] = 0;
+ data[4] = 0;
+ data[5] = 0;
+ data[6] = entry_num;
+ data[7] = 0;
+
+ for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
+ retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, WAIT_INT, data, 8);
+ if (retval == STATUS_SUCCESS) {
+ break;
+ }
+ }
+ if (i == MS_MAX_RETRY_COUNT) {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Set TPC Parameter Register to 00
+
+ * It sets the data size of a READ_SHORT_DATA and a WRITE_SHORT_DATA TPC
+ * as 32 bytes.
+ */
+int mg_set_tpc_para_sub(struct rts51x_chip *chip, int type, u8 mg_entry_num)
+{
+ int retval;
+ u8 buf[6];
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ if (type == 0) {
+ retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_TPCParm, 1);
+ } else {
+ retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
+ }
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ buf[0] = 0;
+ buf[1] = 0;
+ if (type == 1) {
+ buf[2] = 0;
+ buf[3] = 0;
+ buf[4] = 0;
+ buf[5] = mg_entry_num;
+ }
+ retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6, NO_WAIT_INT, buf, 6);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Get MagciGate ID and set Leaf ID to medium.
+
+ * After receiving this SCSI command, adapter shall fulfill 2 tasks below in order:
+ * 1. send GET_ID TPC command to get MagicGate ID and hold it till Response&challenge CMD.
+ * 2. send SET_ID TPC command to medium with Leaf ID released by host in this SCSI CMD.
+ */
+int mg_set_leaf_id(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int retval;
+ int i;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 buf1[32], buf2[12];
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ if (scsi_bufflen(srb) < 12) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_send_ex_cmd(chip, MG_SET_LID, 0);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ TRACE_RET(chip, retval);
+ }
+
+ memset(buf1, 0, 32);
+ rts51x_get_xfer_buf(buf2, min(12, (int)scsi_bufflen(srb)), srb);
+ for (i = 0; i < 8; i++) {
+ buf1[8+i] = buf2[4+i];
+ }
+ retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf1, 32);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ TRACE_RET(chip, retval);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Send Local EKB to host.
+
+ * After receiving this SCSI command, adapter shall read the divided data(1536 bytes totally)
+ * from medium by using READ_LONG_DATA TPC for 3 times, and report data to host with
+ * data-length is 1052 bytes.
+ */
+int mg_get_local_EKB(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ int retval = STATUS_FAIL;
+ int bufflen;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 *buf = NULL;
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ buf = (u8 *)kmalloc(1540, GFP_KERNEL);
+ if (!buf) {
+ TRACE_RET(chip, STATUS_NOMEM);
+ }
+
+ buf[0] = 0x04;
+ buf[1] = 0x1A;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+
+ retval = mg_send_ex_cmd(chip, MG_GET_LEKB, 0);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_GOTO(chip, GetEKBFinish);
+ }
+
+ retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
+ 3, WAIT_INT, 0, 0, buf + 4, 1536);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ rts51x_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR);
+ TRACE_GOTO(chip, GetEKBFinish);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_GOTO(chip, GetEKBFinish);
+ }
+
+ bufflen = min(1052, (int)scsi_bufflen(srb));
+ rts51x_set_xfer_buf(buf, bufflen, srb);
+
+GetEKBFinish:
+ if (buf) {
+ kfree(buf);
+ }
+ return retval;
+}
+
+/**
+ * Send challenge(host) to medium.
+
+ * After receiving this SCSI command, adapter shall sequentially issues TPC commands
+ * to the medium for writing 8-bytes data as challenge by host within a short data packet.
+ */
+int mg_chg(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+ int bufflen;
+ int i;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 buf[32],tmp;
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_send_ex_cmd(chip, MG_GET_ID, 0);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT, buf, 32);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, retval);
+ }
+
+ memcpy(ms_card->magic_gate_id, buf, 16);
+
+ for (i = 0; i < 2500; i++) {
+ RTS51X_READ_REG(chip, MS_TRANS_CFG, &tmp);
+ if (tmp & (MS_INT_CED | MS_INT_CMDNK | MS_INT_BREQ |MS_INT_ERR)) {
+ break;
+ }
+
+ wait_timeout(1);
+ }
+
+ if (i == 2500) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ retval = mg_send_ex_cmd(chip, MG_SET_RD, 0);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, retval);
+ }
+
+ bufflen = min(12, (int)scsi_bufflen(srb));
+ rts51x_get_xfer_buf(buf, bufflen, srb);
+
+ for (i = 0; i < 8; i++) {
+ buf[i] = buf[4+i];
+ }
+ for (i = 0; i < 24; i++) {
+ buf[8+i] = 0;
+ }
+ retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf, 32);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
+ TRACE_RET(chip, retval);
+ }
+
+ ms_card->mg_auth = 0;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Send Response and Challenge data to host.
+
+ * After receiving this SCSI command, adapter shall communicates with the medium, get
+ * parameters(HRd, Rms, MagicGateID) by using READ_SHORT_DATA TPC and send the
+ * data to host according to certain format required by MG-R specification.
+
+ * The paremeter MagicGateID is the one that adapter has obtained from the medium by TPC
+ * commands in Set Leaf ID command phase previously.
+ */
+int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval,i;
+ int bufflen;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 buf1[32], buf2[36],tmp;
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT, buf1, 32);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, retval);
+ }
+
+ buf2[0] = 0x00;
+ buf2[1] = 0x22;
+ buf2[2] = 0x00;
+ buf2[3] = 0x00;
+
+ memcpy(buf2 + 4, ms_card->magic_gate_id, 16);
+ memcpy(buf2 + 20, buf1, 16);
+
+ bufflen = min(36, (int)scsi_bufflen(srb));
+ rts51x_set_xfer_buf(buf2, bufflen, srb);
+
+ for (i = 0; i < 2500; i++) {
+ RTS51X_READ_REG(chip, MS_TRANS_CFG, &tmp);
+ if (tmp & (MS_INT_CED | MS_INT_CMDNK | MS_INT_BREQ |MS_INT_ERR)) {
+ break;
+ }
+
+ wait_timeout(1);
+ }
+
+ if (i == 2500) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, STATUS_FAIL);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Send response(host) to medium.
+
+ * After receiving this SCSI command, adapter shall sequentially issues TPC commands
+ * to the medium for writing 8-bytes data as challenge by host within a short data packet.
+ */
+int mg_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+ int i;
+ int bufflen;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 buf[32];
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, retval);
+ }
+
+ bufflen = min(12, (int)scsi_bufflen(srb));
+ rts51x_get_xfer_buf(buf, bufflen, srb);
+
+ for (i = 0; i < 8; i++) {
+ buf[i] = buf[4+i];
+ }
+ for (i = 0; i < 24; i++) {
+ buf[8+i] = 0;
+ }
+ retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf, 32);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, retval);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
+ TRACE_RET(chip, retval);
+ }
+
+ ms_card->mg_auth = 1;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Send ICV data to host.
+
+ * After receiving this SCSI command, adapter shall read the divided data(1024 bytes totally)
+ * from medium by using READ_LONG_DATA TPC for 2 times, and report data to host with
+ * data-length is 1028 bytes.
+
+ * Since the extra 4 bytes data is just only a prefix to original data that read from medium, so
+ * that the 4-byte data pushed into Ring buffer precedes data tramsinssion from medium to
+ * Ring buffer by DMA mechanisim in order to get maximum performance and minimum code
+ * size simultaneously.
+ */
+int mg_get_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+ int bufflen;
+ unsigned int lun = SCSI_LUN(srb);
+ u8 *buf = NULL;
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ buf = (u8 *)kmalloc(1028, GFP_KERNEL);
+ if (!buf) {
+ TRACE_RET(chip, STATUS_NOMEM);
+ }
+
+ buf[0] = 0x04;
+ buf[1] = 0x02;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+
+ retval = mg_send_ex_cmd(chip, MG_GET_IBD, ms_card->mg_entry_num);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_GOTO(chip, GetICVFinish);
+ }
+
+ retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
+ 2, WAIT_INT, 0, 0, buf + 4, 1024);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ rts51x_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR);
+ TRACE_GOTO(chip, GetICVFinish);
+ }
+
+ retval = mg_check_int_error(chip);
+ if(retval!=STATUS_SUCCESS)
+ {
+ set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
+ TRACE_GOTO(chip, GetICVFinish);
+ }
+
+ bufflen = min(1028, (int)scsi_bufflen(srb));
+ rts51x_set_xfer_buf(buf, bufflen, srb);
+
+GetICVFinish:
+ if (buf) {
+ kfree(buf);
+ }
+ return retval;
+}
+
+/**
+ * Send ICV data to medium.
+
+ * After receiving this SCSI command, adapter shall receive 1028 bytes and write the later 1024
+ * bytes to medium by WRITE_LONG_DATA TPC consecutively.
+
+ * Since the first 4-bytes data is just only a prefix to original data that sent by host, and it
+ * should be skipped by shifting DMA pointer before writing 1024 bytes to medium.
+ */
+int mg_set_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+{
+ struct ms_info *ms_card = &(chip->ms_card);
+ int retval;
+ int bufflen;
+#ifdef MG_SET_ICV_SLOW
+ int i;
+#endif
+ unsigned int lun = SCSI_LUN(srb);
+ u8 *buf = NULL;
+
+ RTS51X_DEBUGP(("--%s--\n", __FUNCTION__));
+
+ ms_cleanup_work(chip);
+
+ retval = ms_switch_clock(chip);
+ if (retval != STATUS_SUCCESS) {
+ TRACE_RET(chip, retval);
+ }
+
+ buf = (u8 *)kmalloc(1028, GFP_KERNEL);
+ if (!buf) {
+ TRACE_RET(chip, STATUS_NOMEM);
+ }
+
+ bufflen = min(1028, (int)scsi_bufflen(srb));
+ rts51x_get_xfer_buf(buf, bufflen, srb);
+
+ retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num);
+ if (retval != STATUS_SUCCESS) {
+ if (ms_card->mg_auth == 0) {
+ if ((buf[5] & 0xC0) != 0) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ TRACE_GOTO(chip, SetICVFinish);
+ }
+
+#ifdef MG_SET_ICV_SLOW
+ for (i = 0; i < 2; i++) {
+ udelay(50);
+
+ rts51x_init_cmd(chip);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, PRO_WRITE_LONG_DATA);
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, WAIT_INT);
+
+ trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512);
+
+ rts51x_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
+ MS_TRANSFER_START | MS_TM_NORMAL_WRITE);
+ rts51x_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END);
+
+ retval = rts51x_send_cmd(chip, MODE_CDOR, 100);
+ if (retval != STATUS_SUCCESS) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ TRACE_GOTO(chip, SetICVFinish);
+ }
+
+ retval = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
+ buf + 4 + i*512, 512, 0, NULL, 3000, STAGE_DO);
+ if (retval != STATUS_SUCCESS) {
+ rts51x_clear_ms_error(chip);
+ if (ms_card->mg_auth == 0) {
+ if ((buf[5] & 0xC0) != 0) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ retval = STATUS_FAIL;
+ TRACE_GOTO(chip, SetICVFinish);
+ }
+
+ retval = rts51x_get_rsp(chip, 1, 3000);
+
+#ifdef RCC_BUG_FIX_SP
+ if((chip->option.rcc_fail_flag == 2)&&(chip->option.rcc_bug_fix_en==1))
+ {
+ u8 tmpvalue;
+ int num = 0;
+
+ chip->rcc_read_response = 0;
+ rts51x_ep0_read_register(chip, SFSM_ED, &tmpvalue);
+ if(!(tmpvalue&CARD_ERR))
+ {
+ for(num=0;num < 3000;num++)
+ {
+ rts51x_ep0_read_register(chip, MS_TRANSFER, &tmpvalue);
+ if(tmpvalue&MS_TRANSFER_END)
+ {
+ break;
+ }
+ wait_timeout(1);
+ }
+ }
+ if((tmpvalue&MS_TRANSFER_ERR)||(num==3000))
+ {
+ retval = STATUS_FAIL;
+ }
+ else
+ {
+ *chip->rsp_buf = tmpvalue;
+ retval = STATUS_SUCCESS;
+ }
+ rts51x_reset_pipe(chip,0);
+ rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
+ rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
+ }
+#endif
+
+ if (CHECK_MS_TRANS_FAIL(chip, retval)||mg_check_int_error(chip)) {
+ rts51x_clear_ms_error(chip);
+ if (ms_card->mg_auth == 0) {
+ if ((buf[5] & 0xC0) != 0) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ retval = STATUS_FAIL;
+ TRACE_GOTO(chip, SetICVFinish);
+ }
+ }
+#else
+ retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA,
+ 2, WAIT_INT, 0, 0, buf + 4, 1024);
+ if (retval != STATUS_SUCCESS) {
+ rts51x_clear_ms_error(chip);
+ if (ms_card->mg_auth == 0) {
+ if ((buf[5] & 0xC0) != 0) {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ } else {
+ set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
+ }
+ TRACE_GOTO(chip, SetICVFinish);
+ }
+#endif
+
+SetICVFinish:
+ if (buf) {
+ kfree(buf);
+ }
+ return retval;
+}
+
+#endif