Commit 1dac4186 authored by edwin_rong's avatar edwin_rong Committed by Greg Kroah-Hartman

Staging: add driver for Realtek RTS5139 cardreader

This driver is used for Realtek RTS5139 USB cardreader, which
supports many cards, such as SD, MS, XD series cards.
Signed-off-by: default avataredwin_rong <edwin_rong@realsil.com.cn>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent dd89e20d
...@@ -64,6 +64,8 @@ source "drivers/staging/rtl8712/Kconfig" ...@@ -64,6 +64,8 @@ source "drivers/staging/rtl8712/Kconfig"
source "drivers/staging/rts_pstor/Kconfig" source "drivers/staging/rts_pstor/Kconfig"
source "drivers/staging/rts5139/Kconfig"
source "drivers/staging/frontier/Kconfig" source "drivers/staging/frontier/Kconfig"
source "drivers/staging/pohmelfs/Kconfig" source "drivers/staging/pohmelfs/Kconfig"
......
...@@ -25,6 +25,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/ ...@@ -25,6 +25,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/
obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_RTL8192E) += rtl8192e/
obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_RTS_PSTOR) += rts_pstor/ obj-$(CONFIG_RTS_PSTOR) += rts_pstor/
obj-$(CONFIG_RTS5139) += rts5139/
obj-$(CONFIG_SPECTRA) += spectra/ obj-$(CONFIG_SPECTRA) += spectra/
obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_POHMELFS) += pohmelfs/ obj-$(CONFIG_POHMELFS) += pohmelfs/
......
config RTS5139
tristate "Realtek RTS5139 USB card reader support"
depends on USB_SUPPORT && SCSI
help
Say Y here to include driver code to support the Realtek
RTS5139 USB card readers.
If this driver is compiled as a module, it will be named rts5139.
config RTS5139_DEBUG
bool "Realtek RTS5139 Card Reader verbose debug"
depends on RTS5139
help
Say Y here in order to have the rts5139 code generate
verbose debugging messages.
# 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://www.gnu.org/licenses/>.
#
# Author:
# wwang (wei_wang@realsil.com.cn)
# No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
# Maintainer:
# Edwin Rong (edwin_rong@realsil.com.cn)
# No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
#
# Makefile for the RTS51xx USB Card Reader drivers.
#
TARGET_MODULE := rts5139
EXTRA_CFLAGS := -Idrivers/scsi -I$(PWD)
obj-m += $(TARGET_MODULE).o
common-obj := rts51x_transport.o rts51x_scsi.o rts51x_fop.o
$(TARGET_MODULE)-objs := $(common-obj) rts51x.o rts51x_chip.o rts51x_card.o \
xd.o sd.o ms.o sd_cprm.o ms_mg.o
TODO:
- support more USB card reader of Realtek family
- use kernel coding style
- checkpatch.pl fixes
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_DEBUG_H
#define __RTS51X_DEBUG_H
#include <linux/kernel.h>
#define RTS51X_TIP "rts51x: "
#ifdef CONFIG_RTS5139_DEBUG
#define RTS51X_DEBUGP(x...) printk(KERN_DEBUG RTS51X_TIP x)
#define RTS51X_DEBUGPN(x...) printk(KERN_DEBUG x)
#define RTS51X_DEBUGPX(x...) printk(x)
#define RTS51X_DEBUG(x) x
#else
#define RTS51X_DEBUGP(x...)
#define RTS51X_DEBUGPN(x...)
#define RTS51X_DEBUGPX(x...)
#define RTS51X_DEBUG(x)
#endif
#endif /* __RTS51X_DEBUG_H */
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_MS_H
#define __RTS51X_MS_H
#include "rts51x_chip.h"
#define MS_MAX_RETRY_COUNT 3
#define MS_EXTRA_SIZE 0x9
#define WRT_PRTCT 0x01
/* Error Code */
#define MS_NO_ERROR 0x00
#define MS_CRC16_ERROR 0x80
#define MS_TO_ERROR 0x40
#define MS_NO_CARD 0x20
#define MS_NO_MEMORY 0x10
#define MS_CMD_NK 0x08
#define MS_FLASH_READ_ERROR 0x04
#define MS_FLASH_WRITE_ERROR 0x02
#define MS_BREQ_ERROR 0x01
#define MS_NOT_FOUND 0x03
/* Transfer Protocol Command */
#define READ_PAGE_DATA 0x02
#define READ_REG 0x04
#define GET_INT 0x07
#define WRITE_PAGE_DATA 0x0D
#define WRITE_REG 0x0B
#define SET_RW_REG_ADRS 0x08
#define SET_CMD 0x0E
#define PRO_READ_LONG_DATA 0x02
#define PRO_READ_SHORT_DATA 0x03
#define PRO_READ_REG 0x04
#define PRO_READ_QUAD_DATA 0x05
#define PRO_GET_INT 0x07
#define PRO_WRITE_LONG_DATA 0x0D
#define PRO_WRITE_SHORT_DATA 0x0C
#define PRO_WRITE_QUAD_DATA 0x0A
#define PRO_WRITE_REG 0x0B
#define PRO_SET_RW_REG_ADRS 0x08
#define PRO_SET_CMD 0x0E
#define PRO_EX_SET_CMD 0x09
#ifdef SUPPORT_MAGIC_GATE
#define MG_GET_ID 0x40
#define MG_SET_LID 0x41
#define MG_GET_LEKB 0x42
#define MG_SET_RD 0x43
#define MG_MAKE_RMS 0x44
#define MG_MAKE_KSE 0x45
#define MG_SET_IBD 0x46
#define MG_GET_IBD 0x47
#endif
#ifdef XC_POWERCLASS
#define XC_CHG_POWER 0x16
#endif
/* ++ CMD over Memory Stick */
/* Flash CMD */
#define BLOCK_READ 0xAA
#define BLOCK_WRITE 0x55
#define BLOCK_END 0x33
#define BLOCK_ERASE 0x99
#define FLASH_STOP 0xCC
/* Function CMD */
#define SLEEP 0x5A
#define CLEAR_BUF 0xC3
#define MS_RESET 0x3C
/* -- CMD over Memory Stick */
/* ++ CMD over Memory Stick Pro */
/* Flash CMD */
#define PRO_READ_DATA 0x20
#define PRO_WRITE_DATA 0x21
#define PRO_READ_ATRB 0x24
#define PRO_STOP 0x25
#define PRO_ERASE 0x26
#define PRO_READ_2K_DATA 0x27
#define PRO_WRITE_2K_DATA 0x28
/* Function CMD */
#define PRO_FORMAT 0x10
#define PRO_SLEEP 0x11
/* -- CMD over Memory Stick Pro */
/* register inside memory stick */
#define IntReg 0x01
#define StatusReg0 0x02
#define StatusReg1 0x03
#define SystemParm 0x10
#define BlockAdrs 0x11
#define CMDParm 0x14
#define PageAdrs 0x15
#define OverwriteFlag 0x16
#define ManagemenFlag 0x17
#define LogicalAdrs 0x18
#define ReserveArea 0x1A
/* register inside memory pro */
#define Pro_IntReg 0x01
#define Pro_StatusReg 0x02
#define Pro_TypeReg 0x04
#define Pro_IFModeReg 0x05
#define Pro_CatagoryReg 0x06
#define Pro_ClassReg 0x07
#define Pro_SystemParm 0x10
#define Pro_DataCount1 0x11
#define Pro_DataCount0 0x12
#define Pro_DataAddr3 0x13
#define Pro_DataAddr2 0x14
#define Pro_DataAddr1 0x15
#define Pro_DataAddr0 0x16
#define Pro_TPCParm 0x17
#define Pro_CMDParm 0x18
/* define for INT Register */
#define INT_REG_CED 0x80
#define INT_REG_ERR 0x40
#define INT_REG_BREQ 0x20
#define INT_REG_CMDNK 0x01
/* INT signal */
#define INT_CED 0x01
#define INT_ERR 0x02
#define INT_BREQ 0x04
#define INT_CMDNK 0x08
/* define for OverwriteFlag Register */
#define BLOCK_BOOT 0xC0
#define BLOCK_OK 0x80
#define PAGE_OK 0x60
#define DATA_COMPL 0x10
/* define for ManagemenFlag Register */
#define NOT_BOOT_BLOCK 0x4
#define NOT_TRANSLATION_TABLE 0x8
/* Header */
#define HEADER_ID0 (PPBUF_BASE2) /* 0 */
#define HEADER_ID1 (PPBUF_BASE2 + 1) /* 1 */
/* System Entry */
#define DISABLED_BLOCK0 (PPBUF_BASE2 + 0x170 + 4) /* 2 */
#define DISABLED_BLOCK1 (PPBUF_BASE2 + 0x170 + 5) /* 3 */
#define DISABLED_BLOCK2 (PPBUF_BASE2 + 0x170 + 6) /* 4 */
#define DISABLED_BLOCK3 (PPBUF_BASE2 + 0x170 + 7) /* 5 */
/* Boot & Attribute Information */
#define BLOCK_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 2) /* 6 */
#define BLOCK_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 3) /* 7 */
#define BLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 4) /* 8 */
#define BLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 5) /* 9 */
#define EBLOCK_COUNT_0 (PPBUF_BASE2 + 0x1a0 + 6) /* 10 */
#define EBLOCK_COUNT_1 (PPBUF_BASE2 + 0x1a0 + 7) /* 11 */
#define PAGE_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 8) /* 12 */
#define PAGE_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 9) /* 13 */
/* joey 2004-08-07 for MS check Procedure */
#define MS_Device_Type (PPBUF_BASE2 + 0x1D8) /* 14 */
/* end */
/* joey 2004-05-03 */
#define MS_4bit_Support (PPBUF_BASE2 + 0x1D3) /* 15 */
/* end */
#define setPS_NG 1
#define setPS_Error 0
/* define for Pro_SystemParm Register */
#define PARALLEL_8BIT_IF 0x40
#define PARALLEL_4BIT_IF 0x00
#define SERIAL_IF 0x80
/* define for StatusReg0 Register */
#define BUF_FULL 0x10
#define BUF_EMPTY 0x20
/* define for StatusReg1 Register */
#define MEDIA_BUSY 0x80
#define FLASH_BUSY 0x40
#define DATA_ERROR 0x20
#define STS_UCDT 0x10
#define EXTRA_ERROR 0x08
#define STS_UCEX 0x04
#define FLAG_ERROR 0x02
#define STS_UCFG 0x01
#define MS_SHORT_DATA_LEN 32
#define FORMAT_SUCCESS 0
#define FORMAT_FAIL 1
#define FORMAT_IN_PROGRESS 2
#define MS_SET_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag |= 0x80)
#define MS_CLR_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag &= 0x7F)
#define MS_TST_BAD_BLOCK_FLG(ms_card) ((ms_card)->multi_flag & 0x80)
#define CHECK_MS_TRANS_FAIL(chip, retval) \
(((retval) != STATUS_SUCCESS) || \
(chip->rsp_buf[0] & MS_TRANSFER_ERR))
void mspro_polling_format_status(struct rts51x_chip *chip);
void mspro_format_sense(struct rts51x_chip *chip, unsigned int lun);
void mspro_stop_seq_mode(struct rts51x_chip *chip);
int reset_ms_card(struct rts51x_chip *chip);
int ms_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
int mspro_format(struct scsi_cmnd *srb, struct rts51x_chip *chip,
int short_data_len, int quick_format);
void ms_free_l2p_tbl(struct rts51x_chip *chip);
void ms_cleanup_work(struct rts51x_chip *chip);
int ms_power_off_card3v3(struct rts51x_chip *chip);
int release_ms_card(struct rts51x_chip *chip);
int ms_delay_write(struct rts51x_chip *chip);
#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);
#endif
#endif /* __RTS51X_MS_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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 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;
}
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", __func__);
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", __func__);
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", __func__);
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
buf = 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:
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", __func__);
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", __func__);
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", __func__);
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", __func__);
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
buf = 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:
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", __func__);
ms_cleanup_work(chip);
retval = ms_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
buf = 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);
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:
kfree(buf);
return retval;
}
#endif /* SUPPORT_MAGIC_GATE */
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_MS_MG_H
#define __RTS51X_MS_MG_H
#include "rts51x_chip.h"
#include "ms.h"
int mg_set_leaf_id(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int mg_get_local_EKB(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int mg_chg(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int mg_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int mg_get_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int mg_set_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip);
#endif /* __RTS51X_MS_MG_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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/workqueue.h>
#include <linux/errno.h>
#include <linux/freezer.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/utsname.h>
#include <linux/usb.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include "debug.h"
#include "ms.h"
#include "rts51x.h"
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_scsi.h"
#include "rts51x_transport.h"
#include "rts51x_fop.h"
MODULE_DESCRIPTION(RTS51X_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
#ifdef SCSI_SCAN_DELAY
static unsigned int delay_use = 5;
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
#endif
static int auto_delink_en;
module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
static int ss_en;
module_param(ss_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ss_en, "enable selective suspend");
static int ss_delay = 50;
module_param(ss_delay, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ss_delay,
"seconds to delay before entering selective suspend");
static int needs_remote_wakeup;
module_param(needs_remote_wakeup, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(needs_remote_wakeup, "ss state needs remote wakeup supported");
#ifdef SUPPORT_FILE_OP
static const struct file_operations rts51x_fops = {
.owner = THIS_MODULE,
.read = rts51x_read,
.write = rts51x_write,
.unlocked_ioctl = rts51x_ioctl,
.open = rts51x_open,
.release = rts51x_release,
};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver rts51x_class = {
.name = "rts51x%d",
.fops = &rts51x_fops,
.minor_base = 192,
};
#endif
#ifdef CONFIG_PM /* Minimal support for suspend and resume */
static inline void usb_autopm_enable(struct usb_interface *intf)
{
atomic_set(&intf->pm_usage_cnt, 1);
usb_autopm_put_interface(intf);
}
static inline void usb_autopm_disable(struct usb_interface *intf)
{
atomic_set(&intf->pm_usage_cnt, 0);
usb_autopm_get_interface(intf);
}
void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
{
RTS51X_DEBUGP("Ready to enter SS state\n");
usb_autopm_enable(chip->usb->pusb_intf);
}
void rts51x_try_to_exit_ss(struct rts51x_chip *chip)
{
RTS51X_DEBUGP("Exit from SS state\n");
usb_autopm_disable(chip->usb->pusb_intf);
}
int rts51x_suspend(struct usb_interface *iface, pm_message_t message)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
RTS51X_DEBUGP("%s, message.event = 0x%x\n", __func__, message.event);
/* Wait until no command is running */
mutex_lock(&chip->usb->dev_mutex);
chip->fake_card_ready = chip->card_ready;
rts51x_do_before_power_down(chip);
if (message.event == PM_EVENT_AUTO_SUSPEND) {
RTS51X_DEBUGP("Enter SS state");
chip->resume_from_scsi = 0;
RTS51X_SET_STAT(chip, STAT_SS);
} else {
RTS51X_DEBUGP("Enter SUSPEND state");
RTS51X_SET_STAT(chip, STAT_SUSPEND);
}
/* When runtime PM is working, we'll set a flag to indicate
* whether we should autoresume when a SCSI request arrives. */
mutex_unlock(&chip->usb->dev_mutex);
return 0;
}
int rts51x_resume(struct usb_interface *iface)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
RTS51X_DEBUGP("%s\n", __func__);
if (!RTS51X_CHK_STAT(chip, STAT_SS) || !chip->resume_from_scsi) {
mutex_lock(&chip->usb->dev_mutex);
if (chip->option.ss_en) {
if (GET_PM_USAGE_CNT(chip) <= 0) {
/* Remote wake up, increase pm_usage_cnt */
RTS51X_DEBUGP("Incr pm_usage_cnt\n");
SET_PM_USAGE_CNT(chip, 1);
}
}
RTS51X_SET_STAT(chip, STAT_RUN);
rts51x_init_chip(chip);
rts51x_init_cards(chip);
mutex_unlock(&chip->usb->dev_mutex);
}
return 0;
}
int rts51x_reset_resume(struct usb_interface *iface)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
RTS51X_DEBUGP("%s\n", __func__);
mutex_lock(&chip->usb->dev_mutex);
RTS51X_SET_STAT(chip, STAT_RUN);
if (chip->option.ss_en)
SET_PM_USAGE_CNT(chip, 1);
rts51x_init_chip(chip);
rts51x_init_cards(chip);
mutex_unlock(&chip->usb->dev_mutex);
/* FIXME: Notify the subdrivers that they need to reinitialize
* the device */
return 0;
}
#else /* CONFIG_PM */
void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
{
}
void rts51x_try_to_exit_ss(struct rts51x_chip *chip)
{
}
#endif /* CONFIG_PM */
/*
* The next two routines get called just before and just after
* a USB port reset, whether from this driver or a different one.
*/
int rts51x_pre_reset(struct usb_interface *iface)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
RTS51X_DEBUGP("%s\n", __func__);
/* Make sure no command runs during the reset */
mutex_lock(&chip->usb->dev_mutex);
return 0;
}
int rts51x_post_reset(struct usb_interface *iface)
{
struct rts51x_chip *chip = usb_get_intfdata(iface);
RTS51X_DEBUGP("%s\n", __func__);
/* Report the reset to the SCSI core */
/* usb_stor_report_bus_reset(us); */
/* FIXME: Notify the subdrivers that they need to reinitialize
* the device */
mutex_unlock(&chip->usb->dev_mutex);
return 0;
}
static int rts51x_control_thread(void *__chip)
{
struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
struct Scsi_Host *host = rts51x_to_host(chip);
for (;;) {
if (wait_for_completion_interruptible(&chip->usb->cmnd_ready))
break;
if (test_bit(FLIDX_DISCONNECTING, &chip->usb->dflags)) {
RTS51X_DEBUGP("-- exiting from rts51x-control\n");
break;
}
/* lock the device pointers */
mutex_lock(&(chip->usb->dev_mutex));
/* lock access to the state */
scsi_lock(host);
/* When we are called with no command pending, we're done */
if (chip->srb == NULL) {
scsi_unlock(host);
mutex_unlock(&chip->usb->dev_mutex);
RTS51X_DEBUGP("-- exiting from control thread\n");
break;
}
/* has the command timed out *already* ? */
if (test_bit(FLIDX_TIMED_OUT, &chip->usb->dflags)) {
chip->srb->result = DID_ABORT << 16;
goto SkipForAbort;
}
scsi_unlock(host);
/* reject the command if the direction indicator
* is UNKNOWN
*/
if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
RTS51X_DEBUGP("UNKNOWN data direction\n");
chip->srb->result = DID_ERROR << 16;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
else if (chip->srb->device->id) {
RTS51X_DEBUGP("Bad target number (%d:%d)\n",
chip->srb->device->id,
chip->srb->device->lun);
chip->srb->result = DID_BAD_TARGET << 16;
}
else if (chip->srb->device->lun > chip->max_lun) {
RTS51X_DEBUGP("Bad LUN (%d:%d)\n",
chip->srb->device->id,
chip->srb->device->lun);
chip->srb->result = DID_BAD_TARGET << 16;
}
/* we've got a command, let's do it! */
else {
RTS51X_DEBUG(scsi_show_command(chip->srb));
rts51x_invoke_transport(chip->srb, chip);
}
/* lock access to the state */
scsi_lock(host);
/* indicate that the command is done */
if (chip->srb->result != DID_ABORT << 16)
chip->srb->scsi_done(chip->srb);
else
SkipForAbort :
RTS51X_DEBUGP("scsi command aborted\n");
/* If an abort request was received we need to signal that
* the abort has finished. The proper test for this is
* the TIMED_OUT flag, not srb->result == DID_ABORT, because
* the timeout might have occurred after the command had
* already completed with a different result code. */
if (test_bit(FLIDX_TIMED_OUT, &chip->usb->dflags)) {
complete(&(chip->usb->notify));
/* Allow USB transfers to resume */
clear_bit(FLIDX_ABORTING, &chip->usb->dflags);
clear_bit(FLIDX_TIMED_OUT, &chip->usb->dflags);
}
/* finished working on this command */
chip->srb = NULL;
scsi_unlock(host);
/* unlock the device pointers */
mutex_unlock(&chip->usb->dev_mutex);
} /* for (;;) */
complete(&chip->usb->control_exit);
/* 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 rts51x_polling_thread(void *__chip)
{
struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
#ifdef SCSI_SCAN_DELAY
/* Wait until SCSI scan finished */
wait_timeout((delay_use + 5) * HZ);
#endif
for (;;) {
wait_timeout(POLLING_INTERVAL);
/* if the device has disconnected, we are free to exit */
if (test_bit(FLIDX_DISCONNECTING, &chip->usb->dflags)) {
RTS51X_DEBUGP("-- exiting from rts51x-polling\n");
break;
}
/* if the device has disconnected, we are free to exit */
/* if (kthread_should_stop()) {
printk(KERN_INFO "Stop polling thread!\n");
break;
} */
#ifdef CONFIG_PM
if (RTS51X_CHK_STAT(chip, STAT_SS) ||
RTS51X_CHK_STAT(chip, STAT_SS_PRE) ||
RTS51X_CHK_STAT(chip, STAT_SUSPEND)) {
continue;
}
if (ss_en) {
if (RTS51X_CHK_STAT(chip, STAT_IDLE)) {
if (chip->ss_counter <
(ss_delay * 1000 / POLLING_INTERVAL)) {
chip->ss_counter++;
} else {
/* Prepare SS state */
RTS51X_SET_STAT(chip, STAT_SS_PRE);
rts51x_try_to_enter_ss(chip);
continue;
}
} else {
chip->ss_counter = 0;
}
}
#endif
mspro_polling_format_status(chip);
/* lock the device pointers */
mutex_lock(&(chip->usb->dev_mutex));
rts51x_polling_func(chip);
/* unlock the device pointers */
mutex_unlock(&chip->usb->dev_mutex);
} /* for (;;) */
complete(&chip->usb->polling_exit);
/* 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;
}
#ifdef SCSI_SCAN_DELAY
/* Thread to carry out delayed SCSI-device scanning */
static int rts51x_scan_thread(void *__chip)
{
struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
printk(KERN_DEBUG
"rts51x: device found at %d\n", chip->usb->pusb_dev->devnum);
set_freezable();
/* Wait for the timeout to expire or for a disconnect */
if (delay_use > 0) {
printk(KERN_DEBUG "rts51x: waiting for device "
"to settle before scanning\n");
wait_event_freezable_timeout(chip->usb->delay_wait,
test_bit(FLIDX_DONT_SCAN,
&chip->usb->dflags),
delay_use * HZ);
}
/* If the device is still connected, perform the scanning */
if (!test_bit(FLIDX_DONT_SCAN, &chip->usb->dflags)) {
scsi_scan_host(rts51x_to_host(chip));
printk(KERN_DEBUG "rts51x: device scan complete\n");
/* Should we unbind if no devices were detected? */
}
complete_and_exit(&chip->usb->scanning_done, 0);
}
#endif
/* Associate our private data with the USB device */
static int associate_dev(struct rts51x_chip *chip, struct usb_interface *intf)
{
struct rts51x_usb *rts51x = chip->usb;
#ifdef SUPPORT_FILE_OP
int retval;
#endif
/* Fill in the device-related fields */
rts51x->pusb_dev = interface_to_usbdev(intf);
rts51x->pusb_intf = intf;
rts51x->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
RTS51X_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",
le16_to_cpu(rts51x->pusb_dev->descriptor.idVendor),
le16_to_cpu(rts51x->pusb_dev->descriptor.idProduct),
le16_to_cpu(rts51x->pusb_dev->descriptor.bcdDevice));
RTS51X_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n",
intf->cur_altsetting->desc.bInterfaceSubClass,
intf->cur_altsetting->desc.bInterfaceProtocol);
/* Store our private data in the interface */
usb_set_intfdata(intf, chip);
#ifdef SUPPORT_FILE_OP
/* we can register the device now, as it is ready */
retval = usb_register_dev(intf, &rts51x_class);
if (retval) {
/* something prevented us from registering this driver */
RTS51X_DEBUGP("Not able to get a minor for this device.");
usb_set_intfdata(intf, NULL);
return -ENOMEM;
}
#endif
/* Allocate the device-related DMA-mapped buffers */
rts51x->cr = usb_buffer_alloc(rts51x->pusb_dev, sizeof(*rts51x->cr),
GFP_KERNEL, &rts51x->cr_dma);
if (!rts51x->cr) {
RTS51X_DEBUGP("usb_ctrlrequest allocation failed\n");
usb_set_intfdata(intf, NULL);
return -ENOMEM;
}
rts51x->iobuf = usb_buffer_alloc(rts51x->pusb_dev, RTS51X_IOBUF_SIZE,
GFP_KERNEL, &rts51x->iobuf_dma);
if (!rts51x->iobuf) {
RTS51X_DEBUGP("I/O buffer allocation failed\n");
usb_set_intfdata(intf, NULL);
return -ENOMEM;
}
return 0;
}
static void rts51x_init_options(struct rts51x_chip *chip)
{
struct rts51x_option *option = &(chip->option);
option->led_blink_speed = 7;
option->mspro_formatter_enable = 1;
option->fpga_sd_sdr104_clk = CLK_100;
option->fpga_sd_sdr50_clk = CLK_100;
option->fpga_sd_ddr50_clk = CLK_100;
option->fpga_sd_hs_clk = CLK_100;
option->fpga_mmc_52m_clk = CLK_80;
option->fpga_ms_hg_clk = CLK_80;
option->fpga_ms_4bit_clk = CLK_80;
option->asic_sd_sdr104_clk = 98;
option->asic_sd_sdr50_clk = 98;
option->asic_sd_ddr50_clk = 98;
option->asic_sd_hs_clk = 97;
option->asic_mmc_52m_clk = 95;
option->asic_ms_hg_clk = 116;
option->asic_ms_4bit_clk = 77;
option->sd_ddr_tx_phase = 0;
option->mmc_ddr_tx_phase = 1;
option->sd_speed_prior = 0;
option->sd_ctl =
SD_PUSH_POINT_AUTO | SD_SAMPLE_POINT_AUTO | SUPPORT_UHS50_MMC44;
option->ss_en = ss_en;
option->ss_delay = ss_delay;
option->needs_remote_wakeup = needs_remote_wakeup;
option->auto_delink_en = auto_delink_en;
option->FT2_fast_mode = 0;
option->pwr_delay = 800;
option->xd_rw_step = 0;
option->D3318_off_delay = 50;
option->delink_delay = 100;
option->rts5129_D3318_off_enable = 0;
option->sd20_pad_drive = 0;
option->reset_or_rw_fail_set_pad_drive = 1;
option->rcc_fail_flag = 0;
option->rcc_bug_fix_en = 1;
option->debounce_num = 2;
option->polling_time = 100;
option->led_toggle_interval = 6;
option->xd_rwn_step = 0;
option->sd_send_status_en = 0;
option->sdr50_tx_phase = 0x01;
option->sdr50_rx_phase = 0x05;
option->ddr50_tx_phase = 0x09;
option->ddr50_rx_phase = 0x06;
option->sdr50_phase_sel = 0;
option->sd30_pad_drive = 1;
option->ms_errreg_fix = 0;
option->reset_mmc_first = 0;
option->speed_mmc = 1;
option->led_always_on = 0;
}
/* Get the pipe settings */
static int get_pipes(struct rts51x_chip *chip)
{
struct rts51x_usb *rts51x = chip->usb;
struct usb_host_interface *altsetting =
rts51x->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;
/*
* Find the first endpoint of each type we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt-in is OK (necessary for CBI protocol).
* We will ignore any others.
*/
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) {
RTS51X_DEBUGP("Endpoint sanity check failed!"
"Rejecting dev.\n");
return -EIO;
}
/* Calculate and store the pipe values */
rts51x->send_ctrl_pipe = usb_sndctrlpipe(rts51x->pusb_dev, 0);
rts51x->recv_ctrl_pipe = usb_rcvctrlpipe(rts51x->pusb_dev, 0);
rts51x->send_bulk_pipe = usb_sndbulkpipe(rts51x->pusb_dev,
usb_endpoint_num(ep_out));
rts51x->recv_bulk_pipe = usb_rcvbulkpipe(rts51x->pusb_dev,
usb_endpoint_num(ep_in));
if (ep_int) {
rts51x->recv_intr_pipe = usb_rcvintpipe(rts51x->pusb_dev,
usb_endpoint_num
(ep_int));
rts51x->ep_bInterval = ep_int->bInterval;
}
return 0;
}
/* Initialize all the dynamic resources we need */
static int rts51x_acquire_resources(struct rts51x_chip *chip)
{
struct rts51x_usb *rts51x = chip->usb;
int retval;
rts51x->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rts51x->current_urb) {
RTS51X_DEBUGP("URB allocation failed\n");
return -ENOMEM;
}
rts51x->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rts51x->intr_urb) {
RTS51X_DEBUGP("URB allocation failed\n");
return -ENOMEM;
}
chip->cmd_buf = chip->rsp_buf = rts51x->iobuf;
rts51x_init_options(chip);
/* Init rts51xx device */
retval = rts51x_init_chip(chip);
if (retval != STATUS_SUCCESS)
return -EIO;
return 0;
}
/* Release all our dynamic resources */
static void rts51x_release_resources(struct rts51x_chip *chip)
{
RTS51X_DEBUGP("-- %s\n", __func__);
/* Tell the control thread to exit. The SCSI host must
* already have been removed and the DISCONNECTING flag set
* so that we won't accept any more commands.
*/
RTS51X_DEBUGP("-- sending exit command to thread\n");
complete(&chip->usb->cmnd_ready);
if (chip->usb->ctl_thread)
wait_for_completion(&chip->usb->control_exit);
/* kthread_stop(chip->usb->ctl_thread); */
if (chip->usb->polling_thread)
wait_for_completion(&chip->usb->polling_exit);
/* if (chip->usb->polling_thread)
kthread_stop(chip->usb->polling_thread); */
wait_timeout(200);
/* Release rts51xx device here */
rts51x_release_chip(chip);
usb_free_urb(chip->usb->current_urb);
usb_free_urb(chip->usb->intr_urb);
}
/* Dissociate from the USB device */
static void dissociate_dev(struct rts51x_chip *chip)
{
struct rts51x_usb *rts51x = chip->usb;
RTS51X_DEBUGP("-- %s\n", __func__);
/* Free the device-related DMA-mapped buffers */
if (rts51x->cr)
usb_buffer_free(rts51x->pusb_dev, sizeof(*rts51x->cr),
rts51x->cr, rts51x->cr_dma);
if (rts51x->iobuf)
usb_buffer_free(rts51x->pusb_dev, RTS51X_IOBUF_SIZE,
rts51x->iobuf, rts51x->iobuf_dma);
/* Remove our private data from the interface */
usb_set_intfdata(rts51x->pusb_intf, NULL);
#ifdef SUPPORT_FILE_OP
/* give back our minor */
usb_deregister_dev(rts51x->pusb_intf, &rts51x_class);
#endif
kfree(rts51x);
chip->usb = NULL;
}
/* First stage of disconnect processing: stop SCSI scanning,
* remove the host, and stop accepting new commands
*/
static void quiesce_and_remove_host(struct rts51x_chip *chip)
{
struct rts51x_usb *rts51x = chip->usb;
struct Scsi_Host *host = rts51x_to_host(chip);
/* If the device is really gone, cut short reset delays */
if (rts51x->pusb_dev->state == USB_STATE_NOTATTACHED)
set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
#ifdef SCSI_SCAN_DELAY
/* Prevent SCSI-scanning (if it hasn't started yet)
* and wait for the SCSI-scanning thread to stop.
*/
set_bit(FLIDX_DONT_SCAN, &rts51x->dflags);
wake_up(&rts51x->delay_wait);
wait_for_completion(&rts51x->scanning_done);
#endif
/* 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(FLIDX_DISCONNECTING, &rts51x->dflags);
scsi_unlock(host);
#ifdef SCSI_SCAN_DELAY
wake_up(&rts51x->delay_wait);
#endif
}
/* Second stage of disconnect processing: deallocate all resources */
static void release_everything(struct rts51x_chip *chip)
{
rts51x_release_resources(chip);
dissociate_dev(chip);
/* Drop our reference to the host; the SCSI core will free it
* (and "chip" along with it) when the refcount becomes 0. */
scsi_host_put(rts51x_to_host(chip));
}
static int rts51x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct Scsi_Host *host;
struct rts51x_chip *chip;
struct rts51x_usb *rts51x;
int result;
struct task_struct *th;
RTS51X_DEBUGP("%s detected\n", RTS51X_NAME);
rts51x = kzalloc(sizeof(struct rts51x_usb), GFP_KERNEL);
if (!rts51x) {
printk(KERN_WARNING RTS51X_TIP
"Unable to allocate rts51x_usb\n");
return -ENOMEM;
}
/*
* Ask the SCSI layer to allocate a host structure, with extra
* space at the end for our private us_data structure.
*/
host = scsi_host_alloc(&rts51x_host_template, sizeof(*chip));
if (!host) {
printk(KERN_WARNING RTS51X_TIP
"Unable to allocate the scsi host\n");
kfree(rts51x);
return -ENOMEM;
}
/*
* Allow 16-byte CDBs and thus > 2TB
*/
host->max_cmd_len = 16;
chip = host_to_rts51x(host);
memset(chip, 0, sizeof(struct rts51x_chip));
chip->vendor_id = id->idVendor;
chip->product_id = id->idProduct;
mutex_init(&(rts51x->dev_mutex));
init_completion(&rts51x->cmnd_ready);
init_completion(&rts51x->control_exit);
init_completion(&rts51x->polling_exit);
init_completion(&(rts51x->notify));
#ifdef SCSI_SCAN_DELAY
init_waitqueue_head(&rts51x->delay_wait);
init_completion(&rts51x->scanning_done);
#endif
chip->usb = rts51x;
/* Associate the us_data structure with the USB device */
result = associate_dev(chip, intf);
if (result)
goto BadDevice;
/* Find the endpoints and calculate pipe values */
result = get_pipes(chip);
if (result)
goto BadDevice;
/* Acquire all the other resources and add the host */
result = rts51x_acquire_resources(chip);
if (result)
goto BadDevice;
/* Start up our control thread */
th = kthread_run(rts51x_control_thread, chip, RTS51X_CTL_THREAD);
if (IS_ERR(th)) {
printk(KERN_WARNING RTS51X_TIP
"Unable to start control thread\n");
result = PTR_ERR(th);
goto BadDevice;
}
rts51x->ctl_thread = th;
result = scsi_add_host(rts51x_to_host(chip), &rts51x->pusb_intf->dev);
if (result) {
printk(KERN_WARNING RTS51X_TIP "Unable to add the scsi host\n");
goto BadDevice;
}
#ifdef SCSI_SCAN_DELAY
/* Start up the thread for delayed SCSI-device scanning */
th = kthread_create(rts51x_scan_thread, chip, RTS51X_SCAN_THREAD);
if (IS_ERR(th)) {
printk(KERN_WARNING RTS51X_TIP
"Unable to start the device-scanning thread\n");
complete(&rts51x->scanning_done);
quiesce_and_remove_host(chip);
result = PTR_ERR(th);
goto BadDevice;
}
wake_up_process(th);
#else
scsi_scan_host(rts51x_to_host(chip));
#endif
/* Start up our polling thread */
th = kthread_run(rts51x_polling_thread, chip, RTS51X_POLLING_THREAD);
if (IS_ERR(th)) {
printk(KERN_WARNING RTS51X_TIP
"Unable to start polling thread\n");
result = PTR_ERR(th);
goto BadDevice;
}
rts51x->polling_thread = th;
#ifdef CONFIG_PM
if (ss_en) {
rts51x->pusb_intf->needs_remote_wakeup = needs_remote_wakeup;
SET_PM_USAGE_CNT(chip, 1);
RTS51X_DEBUGP("pm_usage_cnt = %d\n", GET_PM_USAGE_CNT(chip));
}
#endif
return 0;
/* We come here if there are any problems */
BadDevice:
RTS51X_DEBUGP("rts51x_probe() failed\n");
release_everything(chip);
return result;
}
static void rts51x_disconnect(struct usb_interface *intf)
{
struct rts51x_chip *chip = (struct rts51x_chip *)usb_get_intfdata(intf);
RTS51X_DEBUGP("rts51x_disconnect() called\n");
quiesce_and_remove_host(chip);
release_everything(chip);
}
/***********************************************************************
* Initialization and registration
***********************************************************************/
struct usb_device_id rts5139_usb_ids[] = {
{USB_DEVICE(0x0BDA, 0x0139)},
{USB_DEVICE(0x0BDA, 0x0129)},
{} /* Terminating entry */
};
EXPORT_SYMBOL_GPL(rts5139_usb_ids);
MODULE_DEVICE_TABLE(usb, rts5139_usb_ids);
struct usb_driver rts51x_driver = {
.name = RTS51X_NAME,
.probe = rts51x_probe,
.disconnect = rts51x_disconnect,
.suspend = rts51x_suspend,
.resume = rts51x_resume,
.reset_resume = rts51x_reset_resume,
.pre_reset = rts51x_pre_reset,
.post_reset = rts51x_post_reset,
.id_table = rts5139_usb_ids,
.soft_unbind = 1,
};
static int __init rts51x_init(void)
{
int retval;
printk(KERN_INFO "Initializing %s USB card reader driver...\n",
RTS51X_NAME);
/* register the driver, return usb_register return code if error */
retval = usb_register(&rts51x_driver);
if (retval == 0) {
printk(KERN_INFO
"Realtek %s USB card reader support registered.\n",
RTS51X_NAME);
}
return retval;
}
static void __exit rts51x_exit(void)
{
RTS51X_DEBUGP("rts51x_exit() called\n");
/* Deregister the driver
* This will cause disconnect() to be called for each
* attached unit
*/
RTS51X_DEBUGP("-- calling usb_deregister()\n");
usb_deregister(&rts51x_driver);
}
module_init(rts51x_init);
module_exit(rts51x_exit);
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_H
#define __RTS51X_H
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/blkdev.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/cdrom.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_devinfo.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#define DRIVER_VERSION "v1.04"
#define RTS51X_DESC "Realtek RTS5139/29 USB card reader driver"
#define RTS51X_NAME "rts5139"
#define RTS51X_CTL_THREAD "rts5139-control"
#define RTS51X_SCAN_THREAD "rts5139-scan"
#define RTS51X_POLLING_THREAD "rts5139-polling"
#define POLLING_IN_THREAD
/* #define SCSI_SCAN_DELAY */
#define SUPPORT_FILE_OP
#define wait_timeout_x(task_state, msecs) \
do { \
set_current_state((task_state)); \
schedule_timeout((msecs) * HZ / 1000); \
} while (0)
#define wait_timeout(msecs) wait_timeout_x(TASK_INTERRUPTIBLE, (msecs))
#define SCSI_LUN(srb) ((srb)->device->lun)
/* Size of the DMA-mapped I/O buffer */
#define RTS51X_IOBUF_SIZE 1024
/* Size of the autosense data buffer */
#define RTS51X_SENSE_SIZE 18
/* Dynamic bitflag definitions (dflags): used in set_bit() etc. */
#define FLIDX_URB_ACTIVE 0 /* current_urb is in use */
#define FLIDX_SG_ACTIVE 1 /* current_sg is in use */
#define FLIDX_ABORTING 2 /* abort is in progress */
#define FLIDX_DISCONNECTING 3 /* disconnect in progress */
#define FLIDX_RESETTING 4 /* device reset in progress */
#define FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */
#define FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */
struct rts51x_chip;
struct rts51x_usb {
/* 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 */
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;
u8 ifnum; /* interface number */
u8 ep_bInterval; /* interrupt interval */
/* control and bulk communications data */
struct urb *current_urb; /* USB requests */
struct urb *intr_urb; /* Interrupt USB request */
struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
struct task_struct *ctl_thread; /* the control thread */
struct task_struct *polling_thread; /* the polling thread */
/* mutual exclusion and synchronization structures */
struct completion cmnd_ready; /* to sleep thread on */
struct completion control_exit; /* control thread exit */
struct completion polling_exit; /* polling thread exit */
struct completion notify; /* thread begin/end */
#ifdef SCSI_SCAN_DELAY
wait_queue_head_t delay_wait; /* wait during scan, reset */
struct completion scanning_done; /* wait for scan thread */
#endif
};
extern struct usb_driver rts51x_driver;
static inline void get_current_time(u8 *timeval_buf, int buf_len)
{
struct timeval tv;
if (!timeval_buf || (buf_len < 8))
return;
do_gettimeofday(&tv);
timeval_buf[0] = (u8) (tv.tv_sec >> 24);
timeval_buf[1] = (u8) (tv.tv_sec >> 16);
timeval_buf[2] = (u8) (tv.tv_sec >> 8);
timeval_buf[3] = (u8) (tv.tv_sec);
timeval_buf[4] = (u8) (tv.tv_usec >> 24);
timeval_buf[5] = (u8) (tv.tv_usec >> 16);
timeval_buf[6] = (u8) (tv.tv_usec >> 8);
timeval_buf[7] = (u8) (tv.tv_usec);
}
#define SND_CTRL_PIPE(chip) ((chip)->usb->send_ctrl_pipe)
#define RCV_CTRL_PIPE(chip) ((chip)->usb->recv_ctrl_pipe)
#define SND_BULK_PIPE(chip) ((chip)->usb->send_bulk_pipe)
#define RCV_BULK_PIPE(chip) ((chip)->usb->recv_bulk_pipe)
#define RCV_INTR_PIPE(chip) ((chip)->usb->recv_intr_pipe)
/* 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)
#define GET_PM_USAGE_CNT(chip) \
atomic_read(&((chip)->usb->pusb_intf->pm_usage_cnt))
#define SET_PM_USAGE_CNT(chip, cnt) \
atomic_set(&((chip)->usb->pusb_intf->pm_usage_cnt), (cnt))
/* Compatible macros while we switch over */
static inline void *usb_buffer_alloc(struct usb_device *dev, size_t size,
gfp_t mem_flags, dma_addr_t *dma)
{
return usb_alloc_coherent(dev, size, mem_flags, dma);
}
static inline void usb_buffer_free(struct usb_device *dev, size_t size,
void *addr, dma_addr_t dma)
{
return usb_free_coherent(dev, size, addr, dma);
}
/* Convert between us_data and the corresponding Scsi_Host */
static inline struct Scsi_Host *rts51x_to_host(struct rts51x_chip *chip)
{
return container_of((void *)chip, struct Scsi_Host, hostdata);
}
static inline struct rts51x_chip *host_to_rts51x(struct Scsi_Host *host)
{
return (struct rts51x_chip *)(host->hostdata);
}
/* struct scsi_cmnd transfer buffer access utilities */
enum xfer_buf_dir { TO_XFER_BUF, FROM_XFER_BUF };
/* General routines provided by the usb-storage standard core */
#ifdef CONFIG_PM
void rts51x_try_to_enter_ss(struct rts51x_chip *chip);
void rts51x_try_to_exit_ss(struct rts51x_chip *chip);
int rts51x_suspend(struct usb_interface *iface, pm_message_t message);
int rts51x_resume(struct usb_interface *iface);
int rts51x_reset_resume(struct usb_interface *iface);
#else
#define rts51x_suspend NULL
#define rts51x_resume NULL
#define rts51x_reset_resume NULL
#endif
extern struct scsi_host_template rts51x_host_template;
#endif /* __RTS51X_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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/workqueue.h>
#include <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "debug.h"
#include "rts51x.h"
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
#include "rts51x_sys.h"
#include "xd.h"
#include "sd.h"
#include "ms.h"
void do_remaining_work(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
struct xd_info *xd_card = &(chip->xd_card);
struct ms_info *ms_card = &(chip->ms_card);
if (chip->card_ready & SD_CARD) {
if (sd_card->seq_mode) {
RTS51X_SET_STAT(chip, STAT_RUN);
sd_card->counter++;
} else {
sd_card->counter = 0;
}
}
if (chip->card_ready & XD_CARD) {
if (xd_card->delay_write.delay_write_flag) {
RTS51X_SET_STAT(chip, STAT_RUN);
xd_card->counter++;
} else {
xd_card->counter = 0;
}
}
if (chip->card_ready & MS_CARD) {
if (CHK_MSPRO(ms_card)) {
if (ms_card->seq_mode) {
RTS51X_SET_STAT(chip, STAT_RUN);
ms_card->counter++;
} else {
ms_card->counter = 0;
}
} else {
if (ms_card->delay_write.delay_write_flag) {
RTS51X_SET_STAT(chip, STAT_RUN);
ms_card->counter++;
} else {
ms_card->counter = 0;
}
}
}
if (sd_card->counter > POLLING_WAIT_CNT)
sd_cleanup_work(chip);
if (xd_card->counter > POLLING_WAIT_CNT)
xd_cleanup_work(chip);
if (ms_card->counter > POLLING_WAIT_CNT)
ms_cleanup_work(chip);
}
void do_reset_xd_card(struct rts51x_chip *chip)
{
int retval;
if (chip->card2lun[XD_CARD] >= MAX_ALLOWED_LUN_CNT)
return;
retval = reset_xd_card(chip);
if (retval == STATUS_SUCCESS) {
chip->card_ready |= XD_CARD;
chip->card_fail &= ~XD_CARD;
chip->rw_card[chip->card2lun[XD_CARD]] = xd_rw;
} else {
chip->card_ready &= ~XD_CARD;
chip->card_fail |= XD_CARD;
chip->capacity[chip->card2lun[XD_CARD]] = 0;
chip->rw_card[chip->card2lun[XD_CARD]] = NULL;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, XD_CLK_EN, 0);
rts51x_send_cmd(chip, MODE_C, 100);
}
}
void do_reset_sd_card(struct rts51x_chip *chip)
{
int retval;
if (chip->card2lun[SD_CARD] >= MAX_ALLOWED_LUN_CNT)
return;
retval = reset_sd_card(chip);
if (retval == STATUS_SUCCESS) {
chip->card_ready |= SD_CARD;
chip->card_fail &= ~SD_CARD;
chip->rw_card[chip->card2lun[SD_CARD]] = sd_rw;
} else {
chip->card_ready &= ~SD_CARD;
chip->card_fail |= SD_CARD;
chip->capacity[chip->card2lun[SD_CARD]] = 0;
chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
rts51x_send_cmd(chip, MODE_C, 100);
}
}
void do_reset_ms_card(struct rts51x_chip *chip)
{
int retval;
if (chip->card2lun[MS_CARD] >= MAX_ALLOWED_LUN_CNT)
return;
retval = reset_ms_card(chip);
if (retval == STATUS_SUCCESS) {
chip->card_ready |= MS_CARD;
chip->card_fail &= ~MS_CARD;
chip->rw_card[chip->card2lun[MS_CARD]] = ms_rw;
} else {
chip->card_ready &= ~MS_CARD;
chip->card_fail |= MS_CARD;
chip->capacity[chip->card2lun[MS_CARD]] = 0;
chip->rw_card[chip->card2lun[MS_CARD]] = NULL;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0);
rts51x_send_cmd(chip, MODE_C, 100);
}
}
void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
u8 *need_release)
{
int retval;
u8 release_map = 0, reset_map = 0;
u8 value;
retval = rts51x_get_card_status(chip, &(chip->card_status));
#ifdef SUPPORT_OCP
chip->ocp_stat = (chip->card_status >> 4) & 0x03;
#endif
if (retval != STATUS_SUCCESS)
goto Exit_Debounce;
if (chip->card_exist) {
rts51x_clear_start_time(chip);
retval = rts51x_read_register(chip, CARD_INT_PEND, &value);
if (retval != STATUS_SUCCESS) {
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH,
FIFO_FLUSH);
rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
value = 0;
}
if (chip->card_exist & XD_CARD) {
if (!(chip->card_status & XD_CD))
release_map |= XD_CARD;
} else if (chip->card_exist & SD_CARD) {
/* if (!(chip->card_status & SD_CD)) { */
if (!(chip->card_status & SD_CD) || (value & SD_INT))
release_map |= SD_CARD;
} else if (chip->card_exist & MS_CARD) {
/* if (!(chip->card_status & MS_CD)) { */
if (!(chip->card_status & MS_CD) || (value & MS_INT))
release_map |= MS_CARD;
}
} else {
if (chip->card_status & XD_CD) {
rts51x_clear_start_time(chip);
reset_map |= XD_CARD;
} else if (chip->card_status & SD_CD) {
rts51x_clear_start_time(chip);
reset_map |= SD_CARD;
} else if (chip->card_status & MS_CD) {
rts51x_clear_start_time(chip);
reset_map |= MS_CARD;
} else {
if (rts51x_check_start_time(chip))
rts51x_set_start_time(chip);
}
}
if (CHECK_PKG(chip, QFN24) && reset_map) {
if (chip->card_exist & XD_CARD) {
reset_map = 0;
goto Exit_Debounce;
}
}
if (reset_map) {
int xd_cnt = 0, sd_cnt = 0, ms_cnt = 0;
int i;
for (i = 0; i < (chip->option.debounce_num); i++) {
retval =
rts51x_get_card_status(chip, &(chip->card_status));
if (retval != STATUS_SUCCESS) {
reset_map = release_map = 0;
goto Exit_Debounce;
}
if (chip->card_status & XD_CD)
xd_cnt++;
else
xd_cnt = 0;
if (chip->card_status & SD_CD)
sd_cnt++;
else
sd_cnt = 0;
if (chip->card_status & MS_CD)
ms_cnt++;
else
ms_cnt = 0;
wait_timeout(30);
}
reset_map = 0;
if (!(chip->card_exist & XD_CARD)
&& (xd_cnt > (chip->option.debounce_num - 1))) {
reset_map |= XD_CARD;
}
if (!(chip->card_exist & SD_CARD)
&& (sd_cnt > (chip->option.debounce_num - 1))) {
reset_map |= SD_CARD;
}
if (!(chip->card_exist & MS_CARD)
&& (ms_cnt > (chip->option.debounce_num - 1))) {
reset_map |= MS_CARD;
}
}
rts51x_write_register(chip, CARD_INT_PEND, XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
Exit_Debounce:
if (need_reset)
*need_reset = reset_map;
if (need_release)
*need_release = release_map;
}
void rts51x_init_cards(struct rts51x_chip *chip)
{
u8 need_reset = 0, need_release = 0;
card_cd_debounce(chip, &need_reset, &need_release);
if (need_release) {
RTS51X_DEBUGP("need_release = 0x%x\n", need_release);
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
#ifdef SUPPORT_OCP
if (chip->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
rts51x_write_register(chip, OCPCTL, MS_OCP_CLEAR,
MS_OCP_CLEAR);
chip->ocp_stat = 0;
RTS51X_DEBUGP("Clear OCP status.\n");
}
#endif
if (need_release & XD_CARD) {
chip->card_exist &= ~XD_CARD;
chip->card_ejected = 0;
if (chip->card_ready & XD_CARD) {
release_xd_card(chip);
chip->rw_card[chip->card2lun[XD_CARD]] = NULL;
clear_bit(chip->card2lun[XD_CARD],
&(chip->lun_mc));
}
}
if (need_release & SD_CARD) {
chip->card_exist &= ~SD_CARD;
chip->card_ejected = 0;
if (chip->card_ready & SD_CARD) {
release_sd_card(chip);
chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
clear_bit(chip->card2lun[SD_CARD],
&(chip->lun_mc));
}
}
if (need_release & MS_CARD) {
chip->card_exist &= ~MS_CARD;
chip->card_ejected = 0;
if (chip->card_ready & MS_CARD) {
release_ms_card(chip);
chip->rw_card[chip->card2lun[MS_CARD]] = NULL;
clear_bit(chip->card2lun[MS_CARD],
&(chip->lun_mc));
}
}
}
if (need_reset && !chip->card_ready) {
RTS51X_DEBUGP("need_reset = 0x%x\n", need_reset);
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
if (need_reset & XD_CARD) {
chip->card_exist |= XD_CARD;
do_reset_xd_card(chip);
} else if (need_reset & SD_CARD) {
chip->card_exist |= SD_CARD;
do_reset_sd_card(chip);
} else if (need_reset & MS_CARD) {
chip->card_exist |= MS_CARD;
do_reset_ms_card(chip);
}
}
}
void rts51x_release_cards(struct rts51x_chip *chip)
{
if (chip->card_ready & SD_CARD) {
sd_cleanup_work(chip);
release_sd_card(chip);
chip->card_ready &= ~SD_CARD;
}
if (chip->card_ready & XD_CARD) {
xd_cleanup_work(chip);
release_xd_card(chip);
chip->card_ready &= ~XD_CARD;
}
if (chip->card_ready & MS_CARD) {
ms_cleanup_work(chip);
release_ms_card(chip);
chip->card_ready &= ~MS_CARD;
}
}
static inline u8 double_depth(u8 depth)
{
return ((depth > 1) ? (depth - 1) : depth);
}
int switch_ssc_clock(struct rts51x_chip *chip, int clk)
{
struct sd_info *sd_card = &(chip->sd_card);
struct ms_info *ms_card = &(chip->ms_card);
int retval;
u8 N = (u8) (clk - 2), min_N, max_N;
u8 mcu_cnt, div, max_div, ssc_depth;
int sd_vpclk_phase_reset = 0;
if (chip->cur_clk == clk)
return STATUS_SUCCESS;
min_N = 60;
max_N = 120;
max_div = CLK_DIV_4;
RTS51X_DEBUGP("Switch SSC clock to %dMHz\n", clk);
if ((clk <= 2) || (N > max_N))
TRACE_RET(chip, STATUS_FAIL);
mcu_cnt = (u8) (60 / clk + 3);
if (mcu_cnt > 15)
mcu_cnt = 15;
/* To make sure that the SSC clock div_n is
* equal or greater than min_N */
div = CLK_DIV_1;
while ((N < min_N) && (div < max_div)) {
N = (N + 2) * 2 - 2;
div++;
}
RTS51X_DEBUGP("N = %d, div = %d\n", N, div);
if (chip->option.ssc_en) {
if (chip->cur_card == SD_CARD) {
if (CHK_SD_SDR104(sd_card)) {
ssc_depth = chip->option.ssc_depth_sd_sdr104;
} else if (CHK_SD_SDR50(sd_card)) {
ssc_depth = chip->option.ssc_depth_sd_sdr50;
} else if (CHK_SD_DDR50(sd_card)) {
ssc_depth =
double_depth(chip->option.
ssc_depth_sd_ddr50);
} else if (CHK_SD_HS(sd_card)) {
ssc_depth =
double_depth(chip->option.ssc_depth_sd_hs);
} else if (CHK_MMC_52M(sd_card)
|| CHK_MMC_DDR52(sd_card)) {
ssc_depth =
double_depth(chip->option.
ssc_depth_mmc_52m);
} else {
ssc_depth =
double_depth(chip->option.
ssc_depth_low_speed);
}
} else if (chip->cur_card == MS_CARD) {
if (CHK_MSPRO(ms_card)) {
if (CHK_HG8BIT(ms_card)) {
ssc_depth =
double_depth(chip->option.
ssc_depth_ms_hg);
} else {
ssc_depth =
double_depth(chip->option.
ssc_depth_ms_4bit);
}
} else {
if (CHK_MS4BIT(ms_card)) {
ssc_depth =
double_depth(chip->option.
ssc_depth_ms_4bit);
} else {
ssc_depth =
double_depth(chip->option.
ssc_depth_low_speed);
}
}
} else {
ssc_depth =
double_depth(chip->option.ssc_depth_low_speed);
}
if (ssc_depth) {
if (div == CLK_DIV_2) {
/* If clock divided by 2, ssc depth must
* be multiplied by 2 */
if (ssc_depth > 1)
ssc_depth -= 1;
else
ssc_depth = SSC_DEPTH_2M;
} else if (div == CLK_DIV_4) {
/* If clock divided by 4, ssc depth must
* be multiplied by 4 */
if (ssc_depth > 2)
ssc_depth -= 2;
else
ssc_depth = SSC_DEPTH_2M;
}
}
} else {
/* Disable SSC */
ssc_depth = 0;
}
RTS51X_DEBUGP("ssc_depth = %d\n", ssc_depth);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0x3F,
(div << 4) | mcu_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CTL2, SSC_DEPTH_MASK,
ssc_depth);
rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N);
if (sd_vpclk_phase_reset) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
}
retval = rts51x_send_cmd(chip, MODE_C, 2000);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (chip->option.ssc_en && ssc_depth)
rts51x_write_register(chip, SSC_CTL1, 0xff, 0xD0);
else
rts51x_write_register(chip, SSC_CTL1, 0xff, 0x50);
udelay(100);
RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, 0);
chip->cur_clk = clk;
return STATUS_SUCCESS;
}
int switch_normal_clock(struct rts51x_chip *chip, int clk)
{
int retval;
u8 sel, div, mcu_cnt;
int sd_vpclk_phase_reset = 0;
if (chip->cur_clk == clk)
return STATUS_SUCCESS;
if (chip->cur_card == SD_CARD) {
struct sd_info *sd_card = &(chip->sd_card);
if (CHK_SD30_SPEED(sd_card) || CHK_MMC_DDR52(sd_card))
sd_vpclk_phase_reset = 1;
}
switch (clk) {
case CLK_20:
RTS51X_DEBUGP("Switch clock to 20MHz\n");
sel = SSC_80;
div = CLK_DIV_4;
mcu_cnt = 5;
break;
case CLK_30:
RTS51X_DEBUGP("Switch clock to 30MHz\n");
sel = SSC_60;
div = CLK_DIV_2;
mcu_cnt = 4;
break;
case CLK_40:
RTS51X_DEBUGP("Switch clock to 40MHz\n");
sel = SSC_80;
div = CLK_DIV_2;
mcu_cnt = 3;
break;
case CLK_50:
RTS51X_DEBUGP("Switch clock to 50MHz\n");
sel = SSC_100;
div = CLK_DIV_2;
mcu_cnt = 3;
break;
case CLK_60:
RTS51X_DEBUGP("Switch clock to 60MHz\n");
sel = SSC_60;
div = CLK_DIV_1;
mcu_cnt = 3;
break;
case CLK_80:
RTS51X_DEBUGP("Switch clock to 80MHz\n");
sel = SSC_80;
div = CLK_DIV_1;
mcu_cnt = 2;
break;
case CLK_100:
RTS51X_DEBUGP("Switch clock to 100MHz\n");
sel = SSC_100;
div = CLK_DIV_1;
mcu_cnt = 2;
break;
/* case CLK_120:
RTS51X_DEBUGP("Switch clock to 120MHz\n");
sel = SSC_120;
div = CLK_DIV_1;
mcu_cnt = 2;
break;
case CLK_150:
RTS51X_DEBUGP("Switch clock to 150MHz\n");
sel = SSC_150;
div = CLK_DIV_1;
mcu_cnt = 2;
break; */
default:
RTS51X_DEBUGP("Try to switch to an illegal clock (%d)\n",
clk);
TRACE_RET(chip, STATUS_FAIL);
}
if (!sd_vpclk_phase_reset) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE,
CLK_CHANGE);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0x3F,
(div << 4) | mcu_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CLK_FPGA_SEL, 0xFF,
sel);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE,
CLK_CHANGE);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK1_CTL,
PHASE_NOT_RESET, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, CLK_DIV, 0x3F,
(div << 4) | mcu_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SSC_CLK_FPGA_SEL, 0xFF,
sel);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
udelay(200);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_VPCLK1_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
udelay(200);
RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, 0);
}
chip->cur_clk = clk;
return STATUS_SUCCESS;
}
int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr,
u16 sec_cnt)
{
int retval;
unsigned int lun = SCSI_LUN(srb);
int i;
if (chip->rw_card[lun] == NULL)
return STATUS_FAIL;
RTS51X_DEBUGP("%s card, sector addr: 0x%x, sector cnt: %d\n",
(srb->sc_data_direction ==
DMA_TO_DEVICE) ? "Write" : "Read", sec_addr, sec_cnt);
chip->rw_need_retry = 0;
for (i = 0; i < 3; i++) {
retval = chip->rw_card[lun] (srb, chip, sec_addr, sec_cnt);
if (retval != STATUS_SUCCESS) {
CATCH_TRIGGER(chip);
if (chip->option.reset_or_rw_fail_set_pad_drive) {
rts51x_write_register(chip, CARD_DRIVE_SEL,
SD20_DRIVE_MASK,
DRIVE_8mA);
}
}
if (!chip->rw_need_retry)
break;
RTS51X_DEBUGP("Retry RW, (i = %d\n)", i);
}
return retval;
}
u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun)
{
if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD)
return (u8) XD_CARD;
else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD)
return (u8) SD_CARD;
else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD)
return (u8) MS_CARD;
return 0;
}
int card_share_mode(struct rts51x_chip *chip, int card)
{
u8 value;
if (card == SD_CARD)
value = CARD_SHARE_SD;
else if (card == MS_CARD)
value = CARD_SHARE_MS;
else if (card == XD_CARD)
value = CARD_SHARE_XD;
else
TRACE_RET(chip, STATUS_FAIL);
RTS51X_WRITE_REG(chip, CARD_SHARE_MODE, CARD_SHARE_MASK, value);
return STATUS_SUCCESS;
}
int rts51x_select_card(struct rts51x_chip *chip, int card)
{
int retval;
if (chip->cur_card != card) {
u8 mod;
if (card == SD_CARD)
mod = SD_MOD_SEL;
else if (card == MS_CARD)
mod = MS_MOD_SEL;
else if (card == XD_CARD)
mod = XD_MOD_SEL;
else
TRACE_RET(chip, STATUS_FAIL);
RTS51X_WRITE_REG(chip, CARD_SELECT, 0x07, mod);
chip->cur_card = card;
retval = card_share_mode(chip, card);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
void eject_card(struct rts51x_chip *chip, unsigned int lun)
{
RTS51X_DEBUGP("eject card\n");
RTS51X_SET_STAT(chip, STAT_RUN);
do_remaining_work(chip);
if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) {
release_sd_card(chip);
chip->card_ejected |= SD_CARD;
chip->card_ready &= ~SD_CARD;
chip->capacity[lun] = 0;
} else if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) {
release_xd_card(chip);
chip->card_ejected |= XD_CARD;
chip->card_ready &= ~XD_CARD;
chip->capacity[lun] = 0;
} else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) {
release_ms_card(chip);
chip->card_ejected |= MS_CARD;
chip->card_ready &= ~MS_CARD;
chip->capacity[lun] = 0;
}
rts51x_write_register(chip, CARD_INT_PEND, XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
}
void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip,
u32 byte_cnt, u8 pack_size)
{
if (pack_size > DMA_1024)
pack_size = DMA_512;
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
RING_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC3, 0xFF,
(u8) (byte_cnt >> 24));
rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC2, 0xFF,
(u8) (byte_cnt >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC1, 0xFF,
(u8) (byte_cnt >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_TC0, 0xFF, (u8) byte_cnt);
if (dir == DMA_FROM_DEVICE) {
rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_CTL,
0x03 | DMA_PACK_SIZE_MASK,
DMA_DIR_FROM_CARD | DMA_EN | pack_size);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, MC_DMA_CTL,
0x03 | DMA_PACK_SIZE_MASK,
DMA_DIR_TO_CARD | DMA_EN | pack_size);
}
}
int enable_card_clock(struct rts51x_chip *chip, u8 card)
{
u8 clk_en = 0;
if (card & XD_CARD)
clk_en |= XD_CLK_EN;
if (card & SD_CARD)
clk_en |= SD_CLK_EN;
if (card & MS_CARD)
clk_en |= MS_CLK_EN;
RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, clk_en);
return STATUS_SUCCESS;
}
int disable_card_clock(struct rts51x_chip *chip, u8 card)
{
u8 clk_en = 0;
if (card & XD_CARD)
clk_en |= XD_CLK_EN;
if (card & SD_CARD)
clk_en |= SD_CLK_EN;
if (card & MS_CARD)
clk_en |= MS_CLK_EN;
RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, 0);
return STATUS_SUCCESS;
}
int card_power_on(struct rts51x_chip *chip, u8 card)
{
u8 mask, val1, val2;
mask = POWER_MASK;
val1 = PARTIAL_POWER_ON;
val2 = POWER_ON;
#ifdef SD_XD_IO_FOLLOW_PWR
if ((card == SD_CARD) || (card == XD_CARD)) {
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask | LDO3318_PWR_MASK,
val1 | LDO_SUSPEND);
/* RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
LDO3318_PWR_MASK, LDO_SUSPEND); */
}
/* else if(card==XD_CARD)
{
RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND);
//RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
// LDO3318_PWR_MASK, LDO_SUSPEND);
} */
else {
#endif
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val1);
#ifdef SD_XD_IO_FOLLOW_PWR
}
#endif
udelay(chip->option.pwr_delay);
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val2);
#ifdef SD_XD_IO_FOLLOW_PWR
if (card == SD_CARD) {
rts51x_write_register(chip, CARD_PWR_CTL, LDO3318_PWR_MASK,
LDO_ON);
}
#endif
return STATUS_SUCCESS;
}
int card_power_off(struct rts51x_chip *chip, u8 card)
{
u8 mask, val;
mask = POWER_MASK;
val = POWER_OFF;
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val);
return STATUS_SUCCESS;
}
int monitor_card_cd(struct rts51x_chip *chip, u8 card)
{
int retval;
u8 card_cd[32] = { 0 };
card_cd[SD_CARD] = SD_CD;
card_cd[XD_CARD] = XD_CD;
card_cd[MS_CARD] = MS_CD;
retval = rts51x_get_card_status(chip, &(chip->card_status));
if (retval != STATUS_SUCCESS)
return CD_NOT_EXIST;
if (chip->card_status & card_cd[card])
return CD_EXIST;
return CD_NOT_EXIST;
}
int toggle_gpio(struct rts51x_chip *chip, u8 gpio)
{
int retval;
u8 temp_reg;
u8 gpio_output[4] = {
0x01,
};
u8 gpio_oe[4] = {
0x02,
};
if (chip->rts5179) {
retval = rts51x_ep0_read_register(chip, CARD_GPIO, &temp_reg);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
temp_reg ^= gpio_oe[gpio];
temp_reg &= 0xfe; /* bit 0 always set 0 */
retval =
rts51x_ep0_write_register(chip, CARD_GPIO, 0x03, temp_reg);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
} else {
retval = rts51x_ep0_read_register(chip, CARD_GPIO, &temp_reg);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
temp_reg ^= gpio_output[gpio];
retval =
rts51x_ep0_write_register(chip, CARD_GPIO, 0xFF,
temp_reg | gpio_oe[gpio]);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
int turn_on_led(struct rts51x_chip *chip, u8 gpio)
{
int retval;
u8 gpio_oe[4] = {
0x02,
};
u8 gpio_mask[4] = {
0x03,
};
retval =
rts51x_ep0_write_register(chip, CARD_GPIO, gpio_mask[gpio],
gpio_oe[gpio]);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
int turn_off_led(struct rts51x_chip *chip, u8 gpio)
{
int retval;
u8 gpio_output[4] = {
0x01,
};
u8 gpio_oe[4] = {
0x02,
};
u8 gpio_mask[4] = {
0x03,
};
retval =
rts51x_ep0_write_register(chip, CARD_GPIO, gpio_mask[gpio],
gpio_oe[gpio] | gpio_output[gpio]);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_CARD_H
#define __RTS51X_CARD_H
#include "rts51x_chip.h"
/* Register bit definition */
/* Card Power Control Register */
#define POWER_OFF 0x03
#define PARTIAL_POWER_ON 0x02
#define POWER_ON 0x00
#define POWER_MASK 0x03
#define LDO3318_PWR_MASK 0x0C
#define LDO_ON 0x00
#define LDO_SUSPEND 0x08
#define LDO_OFF 0x0C
#define DV3318_AUTO_PWR_OFF 0x10
#define FORCE_LDO_POWERB 0x60
/* Card Output Enable Register */
#define XD_OUTPUT_EN 0x02
#define SD_OUTPUT_EN 0x04
#define MS_OUTPUT_EN 0x08
/* System Clock Control Register */
/* System Clock Divider Register */
#define CLK_CHANGE 0x80
#define CLK_DIV_1 0x00
#define CLK_DIV_2 0x01
#define CLK_DIV_4 0x02
#define CLK_DIV_8 0x03
/* System Clock Select Register */
#define SSC_60 0
#define SSC_80 1
#define SSC_100 2
#define SSC_120 3
#define SSC_150 4
/* Card Clock Enable Register */
#define XD_CLK_EN 0x02
#define SD_CLK_EN 0x04
#define MS_CLK_EN 0x08
/* Card Select Register */
#define XD_MOD_SEL 1
#define SD_MOD_SEL 2
#define MS_MOD_SEL 3
/* Card Transfer Reset Register */
#define XD_STOP 0x02
#define SD_STOP 0x04
#define MS_STOP 0x08
#define XD_CLR_ERR 0x20
#define SD_CLR_ERR 0x40
#define MS_CLR_ERR 0x80
/* SD30_drive_sel */
#define SD30_DRIVE_MASK 0x07
/* CARD_DRIVE_SEL */
#define SD20_DRIVE_MASK 0x03
#define DRIVE_4mA 0x00
#define DRIVE_8mA 0x01
#define DRIVE_12mA 0x02
/* FPGA_PULL_CTL */
#define FPGA_MS_PULL_CTL_EN 0xEF
#define FPGA_SD_PULL_CTL_EN 0xF7
#define FPGA_XD_PULL_CTL_EN1 0xFE
#define FPGA_XD_PULL_CTL_EN2 0xFD
#define FPGA_XD_PULL_CTL_EN3 0xFB
#define FPGA_MS_PULL_CTL_BIT 0x10
#define FPGA_SD_PULL_CTL_BIT 0x08
/* Card Data Source Register */
#define PINGPONG_BUFFER 0x01
#define RING_BUFFER 0x00
/* SFSM_ED */
#define HW_CMD_STOP 0x80
#define CLR_STAGE_STALL 0x08
#define CARD_ERR 0x10
/* CARD_SHARE_MODE */
#define CARD_SHARE_LQFP48 0x04
#define CARD_SHARE_QFN24 0x00
#define CARD_SHARE_LQFP_SEL 0x04
#define CARD_SHARE_XD 0x00
#define CARD_SHARE_SD 0x01
#define CARD_SHARE_MS 0x02
#define CARD_SHARE_MASK 0x03
/* CARD_AUTO_BLINK */
#define BLINK_ENABLE 0x08
#define BLINK_SPEED_MASK 0x07
/* CARD_GPIO */
#define GPIO_OE 0x02
#define GPIO_OUTPUT 0x01
/* CARD_CLK_SOURCE */
#define CRC_FIX_CLK (0x00 << 0)
#define CRC_VAR_CLK0 (0x01 << 0)
#define CRC_VAR_CLK1 (0x02 << 0)
#define SD30_FIX_CLK (0x00 << 2)
#define SD30_VAR_CLK0 (0x01 << 2)
#define SD30_VAR_CLK1 (0x02 << 2)
#define SAMPLE_FIX_CLK (0x00 << 4)
#define SAMPLE_VAR_CLK0 (0x01 << 4)
#define SAMPLE_VAR_CLK1 (0x02 << 4)
/* DCM_DRP_CTL */
#define DCM_RESET 0x08
#define DCM_LOCKED 0x04
#define DCM_208M 0x00
#define DCM_TX 0x01
#define DCM_RX 0x02
/* DCM_DRP_TRIG */
#define DRP_START 0x80
#define DRP_DONE 0x40
/* DCM_DRP_CFG */
#define DRP_WRITE 0x80
#define DRP_READ 0x00
#define DCM_WRITE_ADDRESS_50 0x50
#define DCM_WRITE_ADDRESS_51 0x51
#define DCM_READ_ADDRESS_00 0x00
#define DCM_READ_ADDRESS_51 0x51
/* HW_VERSION */
#define FPGA_VER 0x80
#define HW_VER_MASK 0x0F
/* CD_DEGLITCH_EN */
#define DISABLE_SD_CD 0x08
#define DISABLE_MS_CD 0x10
#define DISABLE_XD_CD 0x20
#define SD_CD_DEGLITCH_EN 0x01
#define MS_CD_DEGLITCH_EN 0x02
#define XD_CD_DEGLITCH_EN 0x04
/* OCPCTL */
#define CARD_OC_DETECT_EN 0x08
#define CARD_OC_CLR 0x01
/* CARD_DMA1_CTL */
#define EXTEND_DMA1_ASYNC_SIGNAL 0x02
/* HS_USB_STAT */
#define USB_HI_SPEED 0x01
/* CFG_MODE_1 */
#define RTS5179 0x02
/* SYS_DUMMY0 */
#define NYET_EN 0x01
#define NYET_MSAK 0x01
/* SSC_CTL1 */
#define SSC_RSTB 0x80
#define SSC_8X_EN 0x40
#define SSC_FIX_FRAC 0x20
#define SSC_SEL_1M 0x00
#define SSC_SEL_2M 0x08
#define SSC_SEL_4M 0x10
#define SSC_SEL_8M 0x18
/* SSC_CTL2 */
#define SSC_DEPTH_MASK 0x03
#define SSC_DEPTH_DISALBE 0x00
#define SSC_DEPTH_2M 0x01
#define SSC_DEPTH_1M 0x02
#define SSC_DEPTH_512K 0x03
/* LDO_POWER_CFG */
#define TUNE_SD18_MASK 0x1C
#define TUNE_SD18_1V7 0x00
#define TUNE_SD18_1V8 (0x01 << 2)
#define TUNE_SD18_1V9 (0x02 << 2)
#define TUNE_SD18_2V0 (0x03 << 2)
#define TUNE_SD18_2V7 (0x04 << 2)
#define TUNE_SD18_2V8 (0x05 << 2)
#define TUNE_SD18_2V9 (0x06 << 2)
#define TUNE_SD18_3V3 (0x07 << 2)
/* XD_CP_WAITTIME */
#define WAIT_1F 0x00
#define WAIT_3F 0x01
#define WAIT_7F 0x02
#define WAIT_FF 0x03
/* XD_INIT */
#define XD_PWR_OFF_DELAY0 0x00
#define XD_PWR_OFF_DELAY1 0x02
#define XD_PWR_OFF_DELAY2 0x04
#define XD_PWR_OFF_DELAY3 0x06
#define XD_AUTO_PWR_OFF_EN 0xF7
#define XD_NO_AUTO_PWR_OFF 0x08
/* XD_DTCTL */
/* XD_CATCTL */
#define XD_TIME_RWN_1 0x00
#define XD_TIME_RWN_STEP 0x20
#define XD_TIME_RW_1 0x00
#define XD_TIME_RW_STEP 0x04
#define XD_TIME_SETUP_1 0x00
#define XD_TIME_SETUP_STEP 0x01
/* XD_CTL */
#define XD_ECC2_UNCORRECTABLE 0x80
#define XD_ECC2_ERROR 0x40
#define XD_ECC1_UNCORRECTABLE 0x20
#define XD_ECC1_ERROR 0x10
#define XD_RDY 0x04
#define XD_CE_EN 0xFD
#define XD_CE_DISEN 0x02
#define XD_WP_EN 0xFE
#define XD_WP_DISEN 0x01
/* XD_TRANSFER */
#define XD_TRANSFER_START 0x80
#define XD_TRANSFER_END 0x40
#define XD_PPB_EMPTY 0x20
#define XD_ERR 0x10
#define XD_RESET 0x00
#define XD_ERASE 0x01
#define XD_READ_STATUS 0x02
#define XD_READ_ID 0x03
#define XD_READ_REDUNDANT 0x04
#define XD_READ_PAGES 0x05
#define XD_SET_CMD 0x06
#define XD_NORMAL_READ 0x07
#define XD_WRITE_PAGES 0x08
#define XD_NORMAL_WRITE 0x09
#define XD_WRITE_REDUNDANT 0x0A
#define XD_SET_ADDR 0x0B
#define XD_COPY_PAGES 0x0C
/* XD_CFG */
#define XD_PPB_TO_SIE 0x80
#define XD_TO_PPB_ONLY 0x00
#define XD_BA_TRANSFORM 0x40
#define XD_BA_NO_TRANSFORM 0x00
#define XD_NO_CALC_ECC 0x20
#define XD_CALC_ECC 0x00
#define XD_IGNORE_ECC 0x10
#define XD_CHECK_ECC 0x00
#define XD_DIRECT_TO_RB 0x08
#define XD_ADDR_MASK 0x07
#define XD_ADDR_LENGTH_0 0x00
#define XD_ADDR_LENGTH_1 0x01
#define XD_ADDR_LENGTH_2 0x02
#define XD_ADDR_LENGTH_3 0x03
#define XD_ADDR_LENGTH_4 0x04
/* XD_PAGE_STATUS */
#define XD_GPG 0xFF
#define XD_BPG 0x00
/* XD_BLOCK_STATUS */
#define XD_GBLK 0xFF
#define XD_LATER_BBLK 0xF0
/* XD_PARITY */
#define XD_ECC2_ALL1 0x80
#define XD_ECC1_ALL1 0x40
#define XD_BA2_ALL0 0x20
#define XD_BA1_ALL0 0x10
#define XD_BA1_BA2_EQL 0x04
#define XD_BA2_VALID 0x02
#define XD_BA1_VALID 0x01
/* XD_CHK_DATA_STATUS */
#define XD_PGSTS_ZEROBIT_OVER4 0x00
#define XD_PGSTS_NOT_FF 0x02
#define XD_AUTO_CHK_DATA_STATUS 0x01
/* SD_CFG1 */
#define SD_CLK_DIVIDE_0 0x00
#define SD_CLK_DIVIDE_256 0xC0
#define SD_CLK_DIVIDE_128 0x80
#define SD_CLK_DIVIDE_MASK 0xC0
#define SD_BUS_WIDTH_1 0x00
#define SD_BUS_WIDTH_4 0x01
#define SD_BUS_WIDTH_8 0x02
#define SD_ASYNC_FIFO_RST 0x10
#define SD_20_MODE 0x00
#define SD_DDR_MODE 0x04
#define SD_30_MODE 0x08
/* SD_CFG2 */
#define SD_CALCULATE_CRC7 0x00
#define SD_NO_CALCULATE_CRC7 0x80
#define SD_CHECK_CRC16 0x00
#define SD_NO_CHECK_CRC16 0x40
#define SD_WAIT_CRC_TO_EN 0x20
#define SD_WAIT_BUSY_END 0x08
#define SD_NO_WAIT_BUSY_END 0x00
#define SD_CHECK_CRC7 0x00
#define SD_NO_CHECK_CRC7 0x04
#define SD_RSP_LEN_0 0x00
#define SD_RSP_LEN_6 0x01
#define SD_RSP_LEN_17 0x02
/* SD/MMC Response Type Definition */
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_NO_CHECK_CRC7,
* SD_RSP_LEN_0 */
#define SD_RSP_TYPE_R0 0x04
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R1 0x01
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_WAIT_BUSY_END, SD_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R1b 0x09
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_CHECK_CRC7,
* SD_RSP_LEN_17 */
#define SD_RSP_TYPE_R2 0x02
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_NO_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R3 0x05
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_NO_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R4 0x05
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R5 0x01
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R6 0x01
/* SD_CALCULATE_CRC7, SD_CHECK_CRC16,
* SD_NO_WAIT_BUSY_END, SD_CHECK_CRC7,
* SD_RSP_LEN_6 */
#define SD_RSP_TYPE_R7 0x01
/* SD_CFG3 */
#define SD_RSP_80CLK_TIMEOUT_EN 0x01
/* SD_STAT1 */
#define SD_CRC7_ERR 0x80
#define SD_CRC16_ERR 0x40
#define SD_CRC_WRITE_ERR 0x20
#define SD_CRC_WRITE_ERR_MASK 0x1C
#define GET_CRC_TIME_OUT 0x02
#define SD_TUNING_COMPARE_ERR 0x01
/* SD_STAT2 */
#define SD_RSP_80CLK_TIMEOUT 0x01
/* SD_BUS_STAT */
#define SD_CLK_TOGGLE_EN 0x80
#define SD_CLK_FORCE_STOP 0x40
#define SD_DAT3_STATUS 0x10
#define SD_DAT2_STATUS 0x08
#define SD_DAT1_STATUS 0x04
#define SD_DAT0_STATUS 0x02
#define SD_CMD_STATUS 0x01
/* SD_PAD_CTL */
#define SD_IO_USING_1V8 0x80
#define SD_IO_USING_3V3 0x7F
#define TYPE_A_DRIVING 0x00
#define TYPE_B_DRIVING 0x01
#define TYPE_C_DRIVING 0x02
#define TYPE_D_DRIVING 0x03
/* SD_SAMPLE_POINT_CTL */
#define DDR_FIX_RX_DAT 0x00
#define DDR_VAR_RX_DAT 0x80
#define DDR_FIX_RX_DAT_EDGE 0x00
#define DDR_FIX_RX_DAT_14_DELAY 0x40
#define DDR_FIX_RX_CMD 0x00
#define DDR_VAR_RX_CMD 0x20
#define DDR_FIX_RX_CMD_POS_EDGE 0x00
#define DDR_FIX_RX_CMD_14_DELAY 0x10
#define SD20_RX_POS_EDGE 0x00
#define SD20_RX_14_DELAY 0x08
#define SD20_RX_SEL_MASK 0x08
/* SD_PUSH_POINT_CTL */
#define DDR_FIX_TX_CMD_DAT 0x00
#define DDR_VAR_TX_CMD_DAT 0x80
#define DDR_FIX_TX_DAT_14_TSU 0x00
#define DDR_FIX_TX_DAT_12_TSU 0x40
#define DDR_FIX_TX_CMD_NEG_EDGE 0x00
#define DDR_FIX_TX_CMD_14_AHEAD 0x20
#define SD20_TX_NEG_EDGE 0x00
#define SD20_TX_14_AHEAD 0x10
#define SD20_TX_SEL_MASK 0x10
#define DDR_VAR_SDCLK_POL_SWAP 0x01
/* SD_TRANSFER */
#define SD_TRANSFER_START 0x80
#define SD_TRANSFER_END 0x40
#define SD_STAT_IDLE 0x20
#define SD_TRANSFER_ERR 0x10
/* SD Transfer Mode definition */
#define SD_TM_NORMAL_WRITE 0x00
#define SD_TM_AUTO_WRITE_3 0x01
#define SD_TM_AUTO_WRITE_4 0x02
#define SD_TM_AUTO_READ_3 0x05
#define SD_TM_AUTO_READ_4 0x06
#define SD_TM_CMD_RSP 0x08
#define SD_TM_AUTO_WRITE_1 0x09
#define SD_TM_AUTO_WRITE_2 0x0A
#define SD_TM_NORMAL_READ 0x0C
#define SD_TM_AUTO_READ_1 0x0D
#define SD_TM_AUTO_READ_2 0x0E
#define SD_TM_AUTO_TUNING 0x0F
/* SD_VPTX_CTL / SD_VPRX_CTL */
#define PHASE_CHANGE 0x80
#define PHASE_NOT_RESET 0x40
/* SD_DCMPS_TX_CTL / SD_DCMPS_RX_CTL */
#define DCMPS_CHANGE 0x80
#define DCMPS_CHANGE_DONE 0x40
#define DCMPS_ERROR 0x20
#define DCMPS_CURRENT_PHASE 0x1F
/* SD_CMD_STATE */
#define SD_CMD_IDLE 0x80
/* SD_DATA_STATE */
#define SD_DATA_IDLE 0x80
/* MS_BLKEND */
#define SET_BLKEND 0x01
/* MS_CFG */
#define SAMPLE_TIME_RISING 0x00
#define SAMPLE_TIME_FALLING 0x80
#define PUSH_TIME_DEFAULT 0x00
#define PUSH_TIME_ODD 0x40
#define NO_EXTEND_TOGGLE 0x00
#define EXTEND_TOGGLE_CHK 0x20
#define MS_BUS_WIDTH_1 0x00
#define MS_BUS_WIDTH_4 0x10
#define MS_BUS_WIDTH_8 0x18
#define MS_2K_SECTOR_MODE 0x04
#define MS_512_SECTOR_MODE 0x00
#define MS_TOGGLE_TIMEOUT_EN 0x00
#define MS_TOGGLE_TIMEOUT_DISEN 0x01
#define MS_NO_CHECK_INT 0x02
/* MS_TRANS_CFG */
#define WAIT_INT 0x80
#define NO_WAIT_INT 0x00
#define NO_AUTO_READ_INT_REG 0x00
#define AUTO_READ_INT_REG 0x40
#define MS_CRC16_ERR 0x20
#define MS_RDY_TIMEOUT 0x10
#define MS_INT_CMDNK 0x08
#define MS_INT_BREQ 0x04
#define MS_INT_ERR 0x02
#define MS_INT_CED 0x01
/* MS_TRANSFER */
#define MS_TRANSFER_START 0x80
#define MS_TRANSFER_END 0x40
#define MS_TRANSFER_ERR 0x20
#define MS_BS_STATE 0x10
#define MS_TM_READ_BYTES 0x00
#define MS_TM_NORMAL_READ 0x01
#define MS_TM_WRITE_BYTES 0x04
#define MS_TM_NORMAL_WRITE 0x05
#define MS_TM_AUTO_READ 0x08
#define MS_TM_AUTO_WRITE 0x0C
#define MS_TM_SET_CMD 0x06
#define MS_TM_COPY_PAGE 0x07
#define MS_TM_MULTI_READ 0x02
#define MS_TM_MULTI_WRITE 0x03
/* MC_DMA_CTL */
#define DMA_TC_EQ_0 0x80
#define DMA_DIR_TO_CARD 0x00
#define DMA_DIR_FROM_CARD 0x02
#define DMA_EN 0x01
#define DMA_128 (0 << 2)
#define DMA_256 (1 << 2)
#define DMA_512 (2 << 2)
#define DMA_1024 (3 << 2)
#define DMA_PACK_SIZE_MASK 0x0C
/* CARD_INT_PEND */
#define XD_INT 0x10
#define MS_INT 0x08
#define SD_INT 0x04
/* MC_FIFO_CTL */
#define FIFO_FLUSH 0x01
/* AUTO_DELINK_EN */
#define AUTO_DELINK 0x02
#define FORCE_DELINK 0x01
/* MC_DMA_RST */
#define DMA_RESET 0x01
#define SSC_POWER_MASK 0x01
#define SSC_POWER_DOWN 0x01
#define SSC_POWER_ON 0x00
/* OCPCTL */
#define MS_OCP_DETECT_EN 0x08
#define MS_OCP_INT_EN 0x04
#define MS_OCP_INT_CLR 0x02
#define MS_OCP_CLEAR 0x01
/* OCPSTAT */
#define MS_OCP_DETECT 0x80
#define MS_OCP_NOW 0x02
#define MS_OCP_EVER 0x01
/* MC_FIFO_STAT */
#define FIFO_FULL 0x01
#define FIFO_EMPTY 0x02
/* RCCTL */
#define U_HW_CMD_EN_MASK 0x02
#define U_HW_CMD_EN 0x02
#define U_HW_CMD_DIS 0x00
/* Register address */
#define FPDCTL 0xFC00
#define SSC_DIV_N_0 0xFC07
#define SSC_CTL1 0xFC09
#define SSC_CTL2 0xFC0A
#define CFG_MODE_1 0xFC0F
#define RCCTL 0xFC14
#define SYS_DUMMY0 0xFC30
#define XD_CP_WAITTIME 0xFD00
#define XD_CP_PAGELEN 0xFD01
#define XD_CP_READADDR0 0xFD02
#define XD_CP_READADDR1 0xFD03
#define XD_CP_READADDR2 0xFD04
#define XD_CP_READADDR3 0xFD05
#define XD_CP_READADDR4 0xFD06
#define XD_CP_WRITEADDR0 0xFD07
#define XD_CP_WRITEADDR1 0xFD08
#define XD_CP_WRITEADDR2 0xFD09
#define XD_CP_WRITEADDR3 0xFD0A
#define XD_CP_WRITEADDR4 0xFD0B
#define XD_INIT 0xFD10
#define XD_DTCTL 0xFD11
#define XD_CTL 0xFD12
#define XD_TRANSFER 0xFD13
#define XD_CFG 0xFD14
#define XD_ADDRESS0 0xFD15
#define XD_ADDRESS1 0xFD16
#define XD_ADDRESS2 0xFD17
#define XD_ADDRESS3 0xFD18
#define XD_ADDRESS4 0xFD19
#define XD_DAT 0xFD1A
#define XD_PAGE_CNT 0xFD1B
#define XD_PAGE_STATUS 0xFD1C
#define XD_BLOCK_STATUS 0xFD1D
#define XD_BLOCK_ADDR1_L 0xFD1E
#define XD_BLOCK_ADDR1_H 0xFD1F
#define XD_BLOCK_ADDR2_L 0xFD20
#define XD_BLOCK_ADDR2_H 0xFD21
#define XD_BYTE_CNT_L 0xFD22
#define XD_BYTE_CNT_H 0xFD23
#define XD_PARITY 0xFD24
#define XD_ECC_BIT1 0xFD25
#define XD_ECC_BYTE1 0xFD26
#define XD_ECC_BIT2 0xFD27
#define XD_ECC_BYTE2 0xFD28
#define XD_RESERVED0 0xFD29
#define XD_RESERVED1 0xFD2A
#define XD_RESERVED2 0xFD2B
#define XD_RESERVED3 0xFD2C
#define XD_CHK_DATA_STATUS 0xFD2D
#define XD_CATCTL 0xFD2E
#define MS_BLKEND 0xFD30
#define MS_READ_START 0xFD31
#define MS_READ_COUNT 0xFD32
#define MS_WRITE_START 0xFD33
#define MS_WRITE_COUNT 0xFD34
#define MS_COMMAND 0xFD35
#define MS_OLD_BLOCK_0 0xFD36
#define MS_OLD_BLOCK_1 0xFD37
#define MS_NEW_BLOCK_0 0xFD38
#define MS_NEW_BLOCK_1 0xFD39
#define MS_LOG_BLOCK_0 0xFD3A
#define MS_LOG_BLOCK_1 0xFD3B
#define MS_BUS_WIDTH 0xFD3C
#define MS_PAGE_START 0xFD3D
#define MS_PAGE_LENGTH 0xFD3E
#define MS_CFG 0xFD40
#define MS_TPC 0xFD41
#define MS_TRANS_CFG 0xFD42
#define MS_TRANSFER 0xFD43
#define MS_INT_REG 0xFD44
#define MS_BYTE_CNT 0xFD45
#define MS_SECTOR_CNT_L 0xFD46
#define MS_SECTOR_CNT_H 0xFD47
#define MS_DBUS_H 0xFD48
#define CARD_DMA1_CTL 0xFD5C
#define CARD_PULL_CTL1 0xFD60
#define CARD_PULL_CTL2 0xFD61
#define CARD_PULL_CTL3 0xFD62
#define CARD_PULL_CTL4 0xFD63
#define CARD_PULL_CTL5 0xFD64
#define CARD_PULL_CTL6 0xFD65
#define CARD_EXIST 0xFD6F
#define CARD_INT_PEND 0xFD71
#define LDO_POWER_CFG 0xFD7B
#define SD_CFG1 0xFDA0
#define SD_CFG2 0xFDA1
#define SD_CFG3 0xFDA2
#define SD_STAT1 0xFDA3
#define SD_STAT2 0xFDA4
#define SD_BUS_STAT 0xFDA5
#define SD_PAD_CTL 0xFDA6
#define SD_SAMPLE_POINT_CTL 0xFDA7
#define SD_PUSH_POINT_CTL 0xFDA8
#define SD_CMD0 0xFDA9
#define SD_CMD1 0xFDAA
#define SD_CMD2 0xFDAB
#define SD_CMD3 0xFDAC
#define SD_CMD4 0xFDAD
#define SD_CMD5 0xFDAE
#define SD_BYTE_CNT_L 0xFDAF
#define SD_BYTE_CNT_H 0xFDB0
#define SD_BLOCK_CNT_L 0xFDB1
#define SD_BLOCK_CNT_H 0xFDB2
#define SD_TRANSFER 0xFDB3
#define SD_CMD_STATE 0xFDB5
#define SD_DATA_STATE 0xFDB6
#define SD_VPCLK0_CTL 0xFC2A
#define SD_VPCLK1_CTL 0xFC2B
#define SD_DCMPS0_CTL 0xFC2C
#define SD_DCMPS1_CTL 0xFC2D
#define CARD_DMA1_CTL 0xFD5C
#define HW_VERSION 0xFC01
#define SSC_CLK_FPGA_SEL 0xFC02
#define CLK_DIV 0xFC03
#define SFSM_ED 0xFC04
#define CD_DEGLITCH_WIDTH 0xFC20
#define CD_DEGLITCH_EN 0xFC21
#define AUTO_DELINK_EN 0xFC23
#define FPGA_PULL_CTL 0xFC1D
#define CARD_CLK_SOURCE 0xFC2E
#define CARD_SHARE_MODE 0xFD51
#define CARD_DRIVE_SEL 0xFD52
#define CARD_STOP 0xFD53
#define CARD_OE 0xFD54
#define CARD_AUTO_BLINK 0xFD55
#define CARD_GPIO 0xFD56
#define SD30_DRIVE_SEL 0xFD57
#define CARD_DATA_SOURCE 0xFD5D
#define CARD_SELECT 0xFD5E
#define CARD_CLK_EN 0xFD79
#define CARD_PWR_CTL 0xFD7A
#define OCPCTL 0xFD80
#define OCPPARA1 0xFD81
#define OCPPARA2 0xFD82
#define OCPSTAT 0xFD83
#define HS_USB_STAT 0xFE01
#define HS_VCONTROL 0xFE26
#define HS_VSTAIN 0xFE27
#define HS_VLOADM 0xFE28
#define HS_VSTAOUT 0xFE29
#define MC_IRQ 0xFF00
#define MC_IRQEN 0xFF01
#define MC_FIFO_CTL 0xFF02
#define MC_FIFO_BC0 0xFF03
#define MC_FIFO_BC1 0xFF04
#define MC_FIFO_STAT 0xFF05
#define MC_FIFO_MODE 0xFF06
#define MC_FIFO_RD_PTR0 0xFF07
#define MC_FIFO_RD_PTR1 0xFF08
#define MC_DMA_CTL 0xFF10
#define MC_DMA_TC0 0xFF11
#define MC_DMA_TC1 0xFF12
#define MC_DMA_TC2 0xFF13
#define MC_DMA_TC3 0xFF14
#define MC_DMA_RST 0xFF15
/* Memory mapping */
#define RBUF_SIZE_MASK 0xFBFF
#define RBUF_BASE 0xF000
#define PPBUF_BASE1 0xF800
#define PPBUF_BASE2 0xFA00
/* int monitor_card_cd */
#define CD_EXIST 0
#define CD_NOT_EXIST 1
#define DEBOUNCE_CNT 5
int monitor_card_cd(struct rts51x_chip *chip, u8 card);
void do_remaining_work(struct rts51x_chip *chip);
void do_reset_xd_card(struct rts51x_chip *chip);
void do_reset_sd_card(struct rts51x_chip *chip);
void do_reset_ms_card(struct rts51x_chip *chip);
void rts51x_init_cards(struct rts51x_chip *chip);
void rts51x_release_cards(struct rts51x_chip *chip);
int switch_ssc_clock(struct rts51x_chip *chip, int clk);
int switch_normal_clock(struct rts51x_chip *chip, int clk);
int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr,
u16 sec_cnt);
u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun);
int card_share_mode(struct rts51x_chip *chip, int card);
int rts51x_select_card(struct rts51x_chip *chip, int card);
void eject_card(struct rts51x_chip *chip, unsigned int lun);
void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip,
u32 byte_cnt, u8 pack_size);
int enable_card_clock(struct rts51x_chip *chip, u8 card);
int disable_card_clock(struct rts51x_chip *chip, u8 card);
int card_power_on(struct rts51x_chip *chip, u8 card);
int card_power_off(struct rts51x_chip *chip, u8 card);
int toggle_gpio(struct rts51x_chip *chip, u8 gpio);
int turn_on_led(struct rts51x_chip *chip, u8 gpio);
int turn_off_led(struct rts51x_chip *chip, u8 gpio);
static inline int check_card_ready(struct rts51x_chip *chip, unsigned int lun)
{
if (chip->card_ready & chip->lun2card[lun])
return 1;
return 0;
}
static inline int check_card_exist(struct rts51x_chip *chip, unsigned int lun)
{
if (chip->card_exist & chip->lun2card[lun])
return 1;
return 0;
}
static inline int check_card_wp(struct rts51x_chip *chip, unsigned int lun)
{
if (chip->card_wp & chip->lun2card[lun])
return 1;
return 0;
}
static inline int check_card_fail(struct rts51x_chip *chip, unsigned int lun)
{
if (chip->card_fail & chip->lun2card[lun])
return 1;
return 0;
}
static inline int check_card_ejected(struct rts51x_chip *chip, unsigned int lun)
{
if (chip->card_ejected & chip->lun2card[lun])
return 1;
return 0;
}
static inline int check_fake_card_ready(struct rts51x_chip *chip,
unsigned int lun)
{
if (chip->fake_card_ready & chip->lun2card[lun])
return 1;
return 0;
}
static inline u8 get_lun2card(struct rts51x_chip *chip, unsigned int lun)
{
return chip->lun2card[lun];
}
static inline int check_lun_mc(struct rts51x_chip *chip, unsigned int lun)
{
return CHK_BIT(chip->lun_mc, lun);
}
static inline void set_lun_mc(struct rts51x_chip *chip, unsigned int lun)
{
SET_BIT(chip->lun_mc, lun);
}
static inline void clear_lun_mc(struct rts51x_chip *chip, unsigned int lun)
{
CLR_BIT(chip->lun_mc, lun);
}
static inline int switch_clock(struct rts51x_chip *chip, int clk)
{
int retval = 0;
if (chip->asic_code)
retval = switch_ssc_clock(chip, clk);
else
retval = switch_normal_clock(chip, clk);
return retval;
}
static inline void rts51x_clear_xd_error(struct rts51x_chip *chip)
{
rts51x_ep0_write_register(chip, CARD_STOP,
XD_STOP | XD_CLR_ERR, XD_STOP | XD_CLR_ERR);
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
rts51x_ep0_write_register(chip, MC_DMA_RST, DMA_RESET, DMA_RESET);
rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
}
static inline void rts51x_clear_sd_error(struct rts51x_chip *chip)
{
rts51x_ep0_write_register(chip, CARD_STOP,
SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR);
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
rts51x_ep0_write_register(chip, MC_DMA_RST, DMA_RESET, DMA_RESET);
rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
}
static inline void rts51x_clear_ms_error(struct rts51x_chip *chip)
{
rts51x_ep0_write_register(chip, CARD_STOP,
MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR);
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
rts51x_ep0_write_register(chip, MC_DMA_RST, DMA_RESET, DMA_RESET);
rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
}
#endif /* __RTS51X_CARD_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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/workqueue.h>
#include "debug.h"
#include "trace.h"
#include "rts51x.h"
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
#include "rts51x_sys.h"
#include "xd.h"
#include "ms.h"
#include "sd.h"
static int check_sd_speed_prior(u32 sd_speed_prior)
{
int i, fake_para = 0;
/* Check the legality of sd_speed_prior */
for (i = 0; i < 4; i++) {
u8 tmp = (u8) (sd_speed_prior >> (i * 8));
if ((tmp < 0x01) || (tmp > 0x04)) {
fake_para = 1;
break;
}
}
return !fake_para;
}
int rts51x_reset_chip(struct rts51x_chip *chip)
{
int retval;
if (CHECK_PKG(chip, LQFP48)) {
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, LDO3318_PWR_MASK,
LDO_SUSPEND);
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, FORCE_LDO_POWERB,
FORCE_LDO_POWERB);
RTS51X_WRITE_REG(chip, CARD_PULL_CTL1, 0x30, 0x10);
RTS51X_WRITE_REG(chip, CARD_PULL_CTL5, 0x03, 0x01);
RTS51X_WRITE_REG(chip, CARD_PULL_CTL6, 0x0C, 0x04);
}
if (chip->asic_code) {
RTS51X_WRITE_REG(chip, SYS_DUMMY0, NYET_MSAK, NYET_EN);
RTS51X_WRITE_REG(chip, CD_DEGLITCH_WIDTH, 0xFF, 0x08);
rts51x_write_register(chip, CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN,
0x00);
rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK,
chip->option.sd30_pad_drive);
rts51x_write_register(chip, CARD_DRIVE_SEL, SD20_DRIVE_MASK,
chip->option.sd20_pad_drive);
if (chip->rts5179)
rts51x_write_register(chip, CARD_PULL_CTL5, 0x03, 0x01);
if (!chip->option.ww_enable) {
if (CHECK_PKG(chip, LQFP48)) {
rts51x_write_register(chip, CARD_PULL_CTL3,
0x80, 0x80);
rts51x_write_register(chip, CARD_PULL_CTL6,
0xf0, 0xA0);
} else {
rts51x_write_register(chip, CARD_PULL_CTL1,
0x30, 0x20);
rts51x_write_register(chip, CARD_PULL_CTL3,
0x80, 0x80);
rts51x_write_register(chip, CARD_PULL_CTL6,
0x0c, 0x08);
}
}
}
if (chip->option.sd_ctl & SUPPORT_UHS50_MMC44) {
SET_UHS50(chip);
RTS51X_DEBUGP("option enable UHS50&MMC44,sd_ctl:0x%x\n",
chip->option.sd_ctl);
} else {
/* if(CHECK_PID(chip, 0x0139)&&CHECK_PKG(chip, LQFP48)) */
if ((CHECK_PID(chip, 0x0139) && CHECK_PKG(chip, LQFP48))
|| chip->rts5179) {
SET_UHS50(chip);
RTS51X_DEBUGP("PID enable UHS50&MMC44\n");
} else {
CLEAR_UHS50(chip);
RTS51X_DEBUGP("PID disable UHS50&MMC44\n");
}
}
if (chip->option.ms_errreg_fix && (chip->ic_version > 1))
rts51x_write_register(chip, 0xFD4D, 0x01, 0x01);
retval = rts51x_write_phy_register(chip, 0xC2, 0x7C);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
rts51x_init_cmd(chip);
/* GPIO OE */
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE);
#ifdef LED_AUTO_BLINK
/* LED autoblink */
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_AUTO_BLINK,
BLINK_ENABLE | BLINK_SPEED_MASK,
BLINK_ENABLE | chip->option.led_blink_speed);
#endif
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#ifdef SUPPORT_OCP
if (chip->asic_code) {
rts51x_write_register(chip, OCPCTL, MS_OCP_DETECT_EN,
MS_OCP_DETECT_EN);
RTS51X_DEBUGP("Enable OCP detect!\n");
}
#endif
if (chip->option.FT2_fast_mode) {
card_power_on(chip, SD_CARD | MS_CARD | XD_CARD);
wait_timeout(10);
}
rts51x_clear_start_time(chip);
return STATUS_SUCCESS;
}
int rts51x_init_chip(struct rts51x_chip *chip)
{
int retval;
u8 val;
chip->max_lun = 0;
chip->cur_clk = 0;
chip->cur_card = 0;
chip->card2lun[XD_CARD] = 0;
chip->card2lun[SD_CARD] = 0;
chip->card2lun[MS_CARD] = 0;
chip->card_ejected = 0;
chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD;
#if 0
chip->option.sdr50_tx_phase = 0x01;
chip->option.sdr50_rx_phase = 0x05;
chip->option.ddr50_tx_phase = 0x09;
chip->option.ddr50_rx_phase = 0x06; /* add for debug */
#endif
#ifdef CLOSE_SSC_POWER
rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
udelay(100);
rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
#endif
RTS51X_SET_STAT(chip, STAT_RUN);
RTS51X_READ_REG(chip, HW_VERSION, &val);
if ((val & 0x0f) >= 2)
chip->option.rcc_bug_fix_en = 0;
RTS51X_DEBUGP("rcc bug fix enable:%d\n", chip->option.rcc_bug_fix_en);
RTS51X_DEBUGP("HW_VERSION: 0x%x\n", val);
if (val & FPGA_VER) {
chip->asic_code = 0;
RTS51X_DEBUGP("FPGA!\n");
} else {
chip->asic_code = 1;
RTS51X_DEBUGP("ASIC!\n");
}
chip->ic_version = val & HW_VER_MASK;
if (!check_sd_speed_prior(chip->option.sd_speed_prior))
chip->option.sd_speed_prior = 0x01020403;
RTS51X_DEBUGP("sd_speed_prior = 0x%08x\n",
chip->option.sd_speed_prior);
RTS51X_READ_REG(chip, CARD_SHARE_MODE, &val);
if (val & CARD_SHARE_LQFP_SEL) {
chip->package = LQFP48;
RTS51X_DEBUGP("Package: LQFP48\n");
} else {
chip->package = QFN24;
RTS51X_DEBUGP("Package: QFN24\n");
}
RTS51X_READ_REG(chip, HS_USB_STAT, &val);
if (val & USB_HI_SPEED) {
chip->usb_speed = USB_20;
RTS51X_DEBUGP("USB High Speed\n");
} else {
chip->usb_speed = USB_11;
RTS51X_DEBUGP("USB Full Speed\n");
}
RTS51X_READ_REG(chip, CFG_MODE_1, &val);
if (val & RTS5179) {
chip->rts5179 = 1;
RTS51X_DEBUGP("device is rts5179\n");
} else {
chip->rts5179 = 0;
}
retval = rts51x_reset_chip(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
int rts51x_release_chip(struct rts51x_chip *chip)
{
xd_free_l2p_tbl(chip);
ms_free_l2p_tbl(chip);
chip->card_ready = 0;
return STATUS_SUCCESS;
}
#ifndef LED_AUTO_BLINK
static inline void rts51x_blink_led(struct rts51x_chip *chip)
{
/* Read/Write */
if (chip->card_ready) {
if (chip->led_toggle_counter <
chip->option.led_toggle_interval) {
chip->led_toggle_counter++;
} else {
chip->led_toggle_counter = 0;
toggle_gpio(chip, LED_GPIO);
}
}
}
#endif
int rts51x_check_start_time(struct rts51x_chip *chip)
{
return 0;
}
void rts51x_set_start_time(struct rts51x_chip *chip)
{
}
void rts51x_clear_start_time(struct rts51x_chip *chip)
{
}
static void rts51x_auto_delink_cmd(struct rts51x_chip *chip)
{
rts51x_write_register(chip, AUTO_DELINK_EN,
AUTO_DELINK, AUTO_DELINK);
}
static void rts51x_auto_delink_force_cmd(struct rts51x_chip *chip)
{
rts51x_write_register(chip, AUTO_DELINK_EN,
AUTO_DELINK | FORCE_DELINK,
AUTO_DELINK | FORCE_DELINK);
}
#ifdef USING_POLLING_CYCLE_DELINK
/* using polling cycle as delink time */
static void rts51x_auto_delink_polling_cycle(struct rts51x_chip *chip)
{
if (chip->auto_delink_counter <=
chip->option.delink_delay * 2) {
if (chip->auto_delink_counter ==
chip->option.delink_delay) {
clear_first_install_mark(chip);
if (chip->card_exist) {
/* False card */
if (!chip->card_ejected) {
/* if card is not ejected or safely
* remove,then do force delink */
RTS51X_DEBUGP("False card inserted,"
"do force delink\n");
rts51x_auto_delink_force_cmd(chip);
chip->auto_delink_counter =
chip->option.delink_delay * 2 + 1;
}
} else {
RTS51X_DEBUGP("No card inserted, do delink\n");
/* rts51x_write_register(chip, CARD_PWR_CTL,
DV3318_AUTO_PWR_OFF, 0); */
rts51x_auto_delink_cmd(chip);
}
}
if (chip->auto_delink_counter ==
chip->option.delink_delay * 2) {
RTS51X_DEBUGP("Try to do force delink\n");
rts51x_auto_delink_force_cmd(chip);
}
chip->auto_delink_counter++;
}
}
static void rts51x_auto_delink(struct rts51x_chip *chip)
{
rts51x_auto_delink_polling_cycle(chip);
}
#else
/* some of called funcs are not implemented, so comment it out */
#if 0
/* using precise time as delink time */
static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
{
int retvalue = 0;
retvalue = rts51x_get_card_status(chip, &chip->card_status);
/* get card CD status success and card CD not exist,
* then check whether delink */
if ((retvalue == STATUS_SUCCESS)
&& (!(chip->card_status & (SD_CD | MS_CD | XD_CD)))) {
if (rts51x_count_delink_time(chip) >=
chip->option.delink_delay) {
clear_first_install_mark(chip);
RTS51X_DEBUGP("No card inserted, do delink\n");
/* sangdy2010-05-17:disable because there is error
* after SSC clock closed and card power
* has been closed before */
/* rts51x_write_register(chip, CARD_PWR_CTL,
DV3318_AUTO_PWR_OFF, 0); */
rts51x_auto_delink_cmd(chip);
}
/* card CD exist and not ready, then do force delink */
if ((retvalue == STATUS_SUCCESS)
&& (chip->card_status & (SD_CD | MS_CD | XD_CD))) {
/* if card is not ejected or safely remove,
* then do force delink */
if (!chip->card_ejected) {
/* sangdy2010-11-16:polling at least 2 cycles
* then do force delink for card may force delink
* if card is extracted and insert quickly
* after ready. */
if (chip->auto_delink_counter > 1) {
if (rts51x_count_delink_time(chip) >
chip->option.delink_delay * 2) {
RTS51X_DEBUGP("Try to do force"
"delink\n");
rts51x_auto_delink_force_cmd(chip);
}
}
}
}
chip->auto_delink_counter++;
}
#else
static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
{
}
#endif
static void rts51x_auto_delink(struct rts51x_chip *chip)
{
rts51x_auto_delink_precise_time(chip);
}
#endif
void rts51x_polling_func(struct rts51x_chip *chip)
{
#ifdef SUPPORT_SD_LOCK
struct sd_info *sd_card = &(chip->sd_card);
if (sd_card->sd_erase_status) {
if (chip->card_exist & SD_CARD) {
u8 val;
rts51x_read_register(chip, SD_BUS_STAT, &val);
if (val & SD_DAT0_STATUS) {
/* Erase completed */
sd_card->sd_erase_status = SD_NOT_ERASE;
sd_card->sd_lock_notify = 1;
/* SD card should be reinited,
* so we release it here. */
sd_cleanup_work(chip);
release_sd_card(chip);
chip->card_ready &= ~SD_CARD;
chip->card_exist &= ~SD_CARD;
chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
clear_bit(chip->card2lun[SD_CARD],
&(chip->lun_mc));
}
} else {
sd_card->sd_erase_status = SD_NOT_ERASE;
}
}
#endif
rts51x_init_cards(chip);
#ifdef SUPPORT_OCP
/* if OCP happen and card exist, then close card OE */
if ((chip->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) &&
(chip->card_exist)) {
rts51x_prepare_run(chip);
if (chip->card_exist & SD_CARD)
rts51x_write_register(chip, CARD_OE, SD_OUTPUT_EN, 0);
else if (chip->card_exist & MS_CARD)
rts51x_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0);
else if (chip->card_exist & XD_CARD)
rts51x_write_register(chip, CARD_OE, XD_OUTPUT_EN, 0);
}
#endif
if (chip->idle_counter < IDLE_MAX_COUNT) {
chip->idle_counter++;
} else {
if (!RTS51X_CHK_STAT(chip, STAT_IDLE)) {
RTS51X_DEBUGP("Idle state!\n");
RTS51X_SET_STAT(chip, STAT_IDLE);
#ifndef LED_AUTO_BLINK
chip->led_toggle_counter = 0;
#endif
/* Idle state, turn off LED
* to reduce power consumption */
if (chip->option.led_always_on
&& (chip->card_exist &
(SD_CARD | MS_CARD | XD_CARD))
&& (!chip->card_ejected)) {
turn_on_led(chip, LED_GPIO);
} else {
if (chip->rts5179) {
rts51x_ep0_write_register(chip,
CARD_GPIO,
0x03, 0x00);
} else {
turn_off_led(chip, LED_GPIO);
}
}
#ifdef CLOSE_SSC_POWER
if (!chip->card_ready) {
rts51x_write_register(chip, CLK_DIV, CLK_CHANGE,
CLK_CHANGE);
rts51x_write_register(chip, FPDCTL,
SSC_POWER_MASK,
SSC_POWER_DOWN);
RTS51X_DEBUGP("Close SSC clock power!\n");
}
#endif
}
}
switch (RTS51X_GET_STAT(chip)) {
case STAT_RUN:
#ifndef LED_AUTO_BLINK
rts51x_blink_led(chip);
#endif
do_remaining_work(chip);
break;
case STAT_IDLE:
break;
default:
break;
}
if (chip->option.auto_delink_en && !chip->card_ready) {
rts51x_auto_delink(chip);
} else {
chip->auto_delink_counter = 0;
rts51x_clear_start_time(chip);
}
}
void rts51x_add_cmd(struct rts51x_chip *chip,
u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
{
int i;
if (chip->cmd_idx < ((CMD_BUF_LEN - CMD_OFFSET) / 4)) {
i = CMD_OFFSET + chip->cmd_idx * 4;
chip->cmd_buf[i++] =
((cmd_type & 0x03) << 6) | (u8) ((reg_addr >> 8) & 0x3F);
chip->cmd_buf[i++] = (u8) reg_addr;
chip->cmd_buf[i++] = mask;
chip->cmd_buf[i++] = data;
chip->cmd_idx++;
}
}
int rts51x_send_cmd(struct rts51x_chip *chip, u8 flag, int timeout)
{
int result;
chip->cmd_buf[CNT_H] = (u8) (chip->cmd_idx >> 8);
chip->cmd_buf[CNT_L] = (u8) (chip->cmd_idx);
chip->cmd_buf[STAGE_FLAG] = flag;
result = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
(void *)(chip->cmd_buf),
chip->cmd_idx * 4 + CMD_OFFSET,
0, NULL, timeout, MODE_C);
if (result != STATUS_SUCCESS)
TRACE_RET(chip, result);
return STATUS_SUCCESS;
}
int rts51x_get_rsp(struct rts51x_chip *chip, int rsp_len, int timeout)
{
int result;
if (rsp_len <= 0)
TRACE_RET(chip, STATUS_ERROR);
/* rsp_len must aligned to dword */
if (rsp_len % 4)
rsp_len += (4 - rsp_len % 4);
result = rts51x_transfer_data_rcc(chip, RCV_BULK_PIPE(chip),
(void *)chip->rsp_buf, rsp_len,
0, NULL, timeout, STAGE_R);
if (result != STATUS_SUCCESS)
TRACE_RET(chip, result);
return STATUS_SUCCESS;
}
int rts51x_get_card_status(struct rts51x_chip *chip, u16 * status)
{
int retval;
u16 val;
#ifdef GET_CARD_STATUS_USING_EPC
retval = rts51x_get_epc_status(chip, &val);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#else
retval = rts51x_ctrl_transfer(chip, RCV_CTRL_PIPE(chip), 0x02, 0xC0,
0, 0, &val, 2, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#endif
if (status)
*status = val;
return STATUS_SUCCESS;
}
int rts51x_write_register(struct rts51x_chip *chip, u16 addr, u8 mask, u8 data)
{
int retval;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, addr, mask, data);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 * data)
{
int retval;
if (data)
*data = 0;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, READ_REG_CMD, addr, 0, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rts51x_get_rsp(chip, 1, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
if (data)
*data = chip->rsp_buf[0];
return STATUS_SUCCESS;
}
int rts51x_ep0_write_register(struct rts51x_chip *chip, u16 addr, u8 mask,
u8 data)
{
int retval;
u16 value = 0, index = 0;
value |= (u16) (3 & 0x03) << 14;
value |= (u16) (addr & 0x3FFF);
index |= (u16) mask << 8;
index |= (u16) data;
retval = rts51x_ctrl_transfer(chip, SND_CTRL_PIPE(chip), 0x00, 0x40,
cpu_to_be16(value), cpu_to_be16(index),
NULL, 0, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 * data)
{
int retval;
u16 value = 0;
u8 val;
if (data)
*data = 0;
value |= (u16) (2 & 0x03) << 14;
value |= (u16) (addr & 0x3FFF);
retval = rts51x_ctrl_transfer(chip, RCV_CTRL_PIPE(chip), 0x00, 0xC0,
cpu_to_be16(value), 0, &val, 1, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (data)
*data = val;
return STATUS_SUCCESS;
}
int rts51x_seq_write_register(struct rts51x_chip *chip, u16 addr, u16 len,
u8 *data)
{
int result;
u16 cmd_len = len + 12;
if (!data)
TRACE_RET(chip, STATUS_ERROR);
cmd_len = (cmd_len <= CMD_BUF_LEN) ? cmd_len : CMD_BUF_LEN;
/* cmd_len must aligned to dword */
if (cmd_len % 4)
cmd_len += (4 - cmd_len % 4);
chip->cmd_buf[0] = 'R';
chip->cmd_buf[1] = 'T';
chip->cmd_buf[2] = 'C';
chip->cmd_buf[3] = 'R';
chip->cmd_buf[PACKET_TYPE] = SEQ_WRITE;
chip->cmd_buf[5] = (u8) (len >> 8);
chip->cmd_buf[6] = (u8) len;
chip->cmd_buf[STAGE_FLAG] = 0;
chip->cmd_buf[8] = (u8) (addr >> 8);
chip->cmd_buf[9] = (u8) addr;
memcpy(chip->cmd_buf + 12, data, len);
result = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
(void *)(chip->cmd_buf), cmd_len, 0,
NULL, 100, MODE_C);
if (result != STATUS_SUCCESS)
TRACE_RET(chip, result);
return STATUS_SUCCESS;
}
int rts51x_seq_read_register(struct rts51x_chip *chip, u16 addr, u16 len,
u8 *data)
{
int result;
u16 rsp_len;
if (!data)
TRACE_RET(chip, STATUS_ERROR);
/* rsp_len must aligned to dword */
if (len % 4)
rsp_len = len + (4 - len % 4);
else
rsp_len = len;
chip->cmd_buf[0] = 'R';
chip->cmd_buf[1] = 'T';
chip->cmd_buf[2] = 'C';
chip->cmd_buf[3] = 'R';
chip->cmd_buf[PACKET_TYPE] = SEQ_READ;
chip->cmd_buf[5] = (u8) (rsp_len >> 8);
chip->cmd_buf[6] = (u8) rsp_len;
chip->cmd_buf[STAGE_FLAG] = STAGE_R;
chip->cmd_buf[8] = (u8) (addr >> 8);
chip->cmd_buf[9] = (u8) addr;
result = rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
(void *)(chip->cmd_buf), 12, 0, NULL,
100, MODE_C);
if (result != STATUS_SUCCESS)
TRACE_RET(chip, result);
result = rts51x_transfer_data_rcc(chip, RCV_BULK_PIPE(chip),
(void *)data, rsp_len, 0, NULL, 100,
STAGE_DI);
if (result != STATUS_SUCCESS)
TRACE_RET(chip, result);
return STATUS_SUCCESS;
}
int rts51x_read_ppbuf(struct rts51x_chip *chip, u8 * buf, int buf_len)
{
int retval;
if (!buf)
TRACE_RET(chip, STATUS_ERROR);
retval =
rts51x_seq_read_register(chip, PPBUF_BASE2, (u16) buf_len, buf);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int rts51x_write_ppbuf(struct rts51x_chip *chip, u8 * buf, int buf_len)
{
int retval;
if (!buf)
TRACE_RET(chip, STATUS_ERROR);
retval =
rts51x_seq_write_register(chip, PPBUF_BASE2, (u16) buf_len, buf);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int rts51x_write_phy_register(struct rts51x_chip *chip, u8 addr, u8 val)
{
int retval;
RTS51X_DEBUGP("Write 0x%x to phy register 0x%x\n", val, addr);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF,
(addr >> 4) & 0x0F);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int rts51x_read_phy_register(struct rts51x_chip *chip, u8 addr, u8 * val)
{
int retval;
RTS51X_DEBUGP("Read from phy register 0x%x\n", addr);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, 0x07);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF,
(addr >> 4) & 0x0F);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
rts51x_add_cmd(chip, READ_REG_CMD, HS_VSTAOUT, 0, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 1, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (val)
*val = chip->rsp_buf[0];
RTS51X_DEBUGP("Return value: 0x%x\n", chip->rsp_buf[0]);
return STATUS_SUCCESS;
}
void rts51x_do_before_power_down(struct rts51x_chip *chip)
{
RTS51X_DEBUGP("rts51x_do_before_power_down\n");
rts51x_prepare_run(chip);
rts51x_release_cards(chip);
if (chip->rts5179)
rts51x_ep0_write_register(chip, CARD_GPIO, 0x03, 0x00);
else
turn_off_led(chip, LED_GPIO);
chip->cur_clk = 0;
chip->card_exist = 0;
chip->cur_card = 0;
if (chip->asic_code && !chip->option.ww_enable) {
if (CHECK_PKG(chip, LQFP48)) {
rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0x50);
} else {
rts51x_write_register(chip, CARD_PULL_CTL1, 0x30, 0x10);
rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
rts51x_write_register(chip, CARD_PULL_CTL6, 0x0c, 0x04);
}
}
if (CHECK_PKG(chip, LQFP48))
rts51x_write_register(chip, CARD_PWR_CTL, LDO3318_PWR_MASK,
LDO_OFF);
}
void rts51x_clear_hw_error(struct rts51x_chip *chip)
{
rts51x_ep0_write_register(chip, SFSM_ED, 0xf8, 0xf8);
}
void rts51x_prepare_run(struct rts51x_chip *chip)
{
#ifdef CLOSE_SSC_POWER
if (RTS51X_CHK_STAT(chip, STAT_IDLE) && (!chip->card_ready)) {
rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK,
SSC_POWER_ON);
udelay(100);
RTS51X_DEBUGP("Open SSC clock power.\n");
rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
}
#endif
#if 0
if (chip->option.ss_en && RTS51X_CHK_STAT(chip, STAT_SS)) {
rts51x_try_to_exit_ss(chip);
wait_timeout(100);
rts51x_init_chip(chip);
rts51x_init_cards(chip);
}
RTS51X_SET_STAT(chip, STAT_RUN);
#endif
}
#ifdef _MSG_TRACE
void rts51x_trace_msg(struct rts51x_chip *chip, unsigned char *buf, int clear)
{
unsigned char *ptr;
int i, msg_cnt;
if (!buf)
return;
ptr = buf;
if (chip->trace_msg[chip->msg_idx].valid)
msg_cnt = TRACE_ITEM_CNT;
else
msg_cnt = chip->msg_idx;
*(ptr++) = (u8) (msg_cnt >> 24);
*(ptr++) = (u8) (msg_cnt >> 16);
*(ptr++) = (u8) (msg_cnt >> 8);
*(ptr++) = (u8) msg_cnt;
RTS51X_DEBUGP("Trace message count is %d\n", msg_cnt);
for (i = 1; i <= msg_cnt; i++) {
int j, idx;
idx = chip->msg_idx - i;
if (idx < 0)
idx += TRACE_ITEM_CNT;
*(ptr++) = (u8) (chip->trace_msg[idx].line >> 8);
*(ptr++) = (u8) (chip->trace_msg[idx].line);
for (j = 0; j < MSG_FUNC_LEN; j++)
*(ptr++) = chip->trace_msg[idx].func[j];
for (j = 0; j < MSG_FILE_LEN; j++)
*(ptr++) = chip->trace_msg[idx].file[j];
for (j = 0; j < TIME_VAL_LEN; j++)
*(ptr++) = chip->trace_msg[idx].timeval_buf[j];
}
if (clear) {
chip->msg_idx = 0;
for (i = 0; i < TRACE_ITEM_CNT; i++)
chip->trace_msg[i].valid = 0;
}
}
#endif
void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 * status,
u8 status_len)
{
struct sd_info *sd_card = &(chip->sd_card);
struct ms_info *ms_card = &(chip->ms_card);
u8 card = get_lun_card(chip, lun);
#ifdef SUPPORT_OC
u8 oc_now_mask = 0, oc_ever_mask = 0;
#endif
if (!status || (status_len < 32))
return;
/* IC Version */
status[0] = (u8) RTS51X_GET_PID(chip);
status[1] = (u8) (chip->ic_version);
/* Auto delink mode */
if (chip->option.auto_delink_en)
status[2] = 0x10;
else
status[2] = 0x00;
/* Spec version */
status[3] = 20;
status[4] = 10;
status[5] = 05;
status[6] = 21;
/* Card WP */
if (chip->card_wp)
status[7] = 0x20;
else
status[7] = 0x00;
#ifdef SUPPORT_OC
/* Over current status */
status[8] = 0;
oc_now_mask = MS_OCP_NOW;
oc_ever_mask = MS_OCP_EVER;
if (chip->ocp_stat & oc_now_mask)
status[8] |= 0x02;
if (chip->ocp_stat & oc_ever_mask)
status[8] |= 0x01;
#endif
if (card == SD_CARD) {
if (CHK_SD(sd_card)) {
if (CHK_SD_HCXC(sd_card)) {
if (sd_card->capacity > 0x4000000)
/* SDXC */
status[0x0E] = 0x02;
else /* SDHC */
status[0x0E] = 0x01;
} else { /* SDSC */
status[0x0E] = 0x00;
}
if (CHK_SD_SDR104(sd_card))
status[0x0F] = 0x03;
else if (CHK_SD_DDR50(sd_card))
status[0x0F] = 0x04;
else if (CHK_SD_SDR50(sd_card))
status[0x0F] = 0x02;
else if (CHK_SD_HS(sd_card))
status[0x0F] = 0x01;
else
status[0x0F] = 0x00; /* Normal speed */
} else {
if (CHK_MMC_SECTOR_MODE(sd_card))
status[0x0E] = 0x01; /* High capacity */
else
status[0x0E] = 0x00; /* Normal capacity */
if (CHK_MMC_DDR52(sd_card))
status[0x0F] = 0x03; /* DDR 52M */
else if (CHK_MMC_52M(sd_card))
status[0x0F] = 0x02; /* SDR 52M */
else if (CHK_MMC_26M(sd_card))
status[0x0F] = 0x01; /* SDR 26M */
else
status[0x0F] = 0x00; /* Normal speed */
}
} else if (card == MS_CARD) {
if (CHK_MSPRO(ms_card)) {
if (CHK_MSXC(ms_card))
status[0x0E] = 0x01; /* XC */
else
status[0x0E] = 0x00;
if (CHK_HG8BIT(ms_card))
status[0x0F] = 0x01;
else
status[0x0F] = 0x00;
}
}
#ifdef SUPPORT_SD_LOCK
/* SD Lock/Unlock */
if (card == SD_CARD) {
status[0x17] = 0x80;
if (sd_card->sd_erase_status)
status[0x17] |= 0x01; /* Under erasing */
if (sd_card->sd_lock_status & SD_LOCKED) {
status[0x17] |= 0x02; /* Locked */
status[0x07] |= 0x40; /* Read protected */
}
if (sd_card->sd_lock_status & SD_PWD_EXIST)
status[0x17] |= 0x04; /* Contain PWD */
} else {
status[0x17] = 0x00;
}
RTS51X_DEBUGP("status[0x17] = 0x%x\n", status[0x17]);
#endif
/* Function 0
* Support Magic Gate, CPRM and PhyRegister R/W */
status[0x18] = 0x8A;
/* Function 2
* Support OC LUN status & WP LUN status */
status[0x1A] = 0x28;
/* Function 7 */
#ifdef SUPPORT_SD_LOCK
/* Support SD Lock/Unlock */
status[0x1F] = 0x01;
#endif
/* Function 2
* Support OC LUN status & WP LUN status */
status[0x1A] = 0x28;
}
void rts51x_read_status(struct rts51x_chip *chip, unsigned int lun,
u8 *rts51x_status, u8 status_len)
{
if (!rts51x_status || (status_len < 16))
return;
/* VID */
rts51x_status[0] = (u8) (RTS51X_GET_VID(chip) >> 8);
rts51x_status[1] = (u8) RTS51X_GET_VID(chip);
/* PID */
rts51x_status[2] = (u8) (RTS51X_GET_PID(chip) >> 8);
rts51x_status[3] = (u8) RTS51X_GET_PID(chip);
/* gbLUN */
rts51x_status[4] = (u8) lun;
/* Lun Card Number */
if (chip->card_exist) {
if (chip->card_exist & XD_CARD)
rts51x_status[5] = 4; /* xD Card */
else if (chip->card_exist & SD_CARD)
rts51x_status[5] = 2; /* SD Card */
else if (chip->card_exist & MS_CARD)
rts51x_status[5] = 3; /* MS Card */
else
rts51x_status[5] = 7; /* Multi */
} else {
rts51x_status[5] = 7; /* Multi */
}
/* Total LUNs */
rts51x_status[6] = 1;
/* IC Version */
rts51x_status[7] = (u8) RTS51X_GET_PID(chip);
rts51x_status[8] = chip->ic_version;
/* Physical Exist */
if (check_card_exist(chip, lun))
rts51x_status[9] = 1;
else
rts51x_status[9] = 0;
/* Multi Flag */
rts51x_status[10] = 1;
/* LUN Valid Map */
rts51x_status[11] = XD_CARD | SD_CARD | MS_CARD;
/* Logical Exist */
if (check_card_ready(chip, lun))
rts51x_status[12] = 1;
else
rts51x_status[12] = 0;
/* Detailed Type */
if (get_lun_card(chip, lun) == XD_CARD) {
rts51x_status[13] = 0x40;
} else if (get_lun_card(chip, lun) == SD_CARD) {
struct sd_info *sd_card = &(chip->sd_card);
rts51x_status[13] = 0x20;
if (CHK_SD(sd_card)) {
if (CHK_SD_HCXC(sd_card))
rts51x_status[13] |= 0x04; /* Hi capacity SD */
if (CHK_SD_HS(sd_card))
rts51x_status[13] |= 0x02; /* Hi speed SD */
} else {
rts51x_status[13] |= 0x08; /* MMC card */
if (CHK_MMC_52M(sd_card))
rts51x_status[13] |= 0x02; /* Hi speed */
if (CHK_MMC_SECTOR_MODE(sd_card))
rts51x_status[13] |= 0x04; /* Hi capacity */
}
} else if (get_lun_card(chip, lun) == MS_CARD) {
struct ms_info *ms_card = &(chip->ms_card);
if (CHK_MSPRO(ms_card)) {
rts51x_status[13] = 0x38; /* MS Pro */
if (CHK_HG8BIT(ms_card))
rts51x_status[13] |= 0x04; /* HG */
#ifdef SUPPORT_MSXC
if (CHK_MSXC(ms_card))
rts51x_status[13] |= 0x01; /* MSXC */
#endif
} else {
rts51x_status[13] = 0x30;
}
} else {
rts51x_status[13] = 0x70;
}
/* Support OC, auto delink, vendor r/w, get bus width */
rts51x_status[14] = 0x78;
rts51x_status[15] = 0x82;
}
int rts51x_transfer_data_rcc(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int len, int use_sg,
unsigned int *act_len, int timeout, u8 stage_flag)
{
int retval;
retval =
rts51x_transfer_data(chip, pipe, buf, len, use_sg, act_len,
timeout);
return retval;
}
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_CHIP_H
#define __RTS51X_CHIP_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 "trace.h"
#define SUPPORT_CPRM
#define SUPPORT_MAGIC_GATE
#define SUPPORT_MSXC
/* #define LED_AUTO_BLINK */
/* { wwang, 2010-07-26
* Add support for SD lock/unlock */
/* #define SUPPORT_SD_LOCK */
/* } wwang, 2010-07-26 */
#ifdef SUPPORT_MAGIC_GA
/* Using NORMAL_WRITE instead of AUTO_WRITE to set ICVTE */
#define MG_SET_ICV_SLOW
#endif
#ifdef SUPPORT_MSXC
#define XC_POWERCLASS
#define SUPPORT_PCGL_1P18
#endif
#define GET_CARD_STATUS_USING_EPC
#define CLOSE_SSC_POWER
#define SUPPORT_OCP
#define MS_SPEEDUP
/* #define XD_SPEEDUP */
#define SD_XD_IO_FOLLOW_PWR
#define SD_NR 2
#define MS_NR 3
#define XD_NR 4
#define SD_CARD (1 << SD_NR)
#define MS_CARD (1 << MS_NR)
#define XD_CARD (1 << XD_NR)
#define SD_CD 0x01
#define MS_CD 0x02
#define XD_CD 0x04
#define SD_WP 0x08
#define MAX_ALLOWED_LUN_CNT 8
#define CMD_BUF_LEN 1024
#define RSP_BUF_LEN 1024
#define POLLING_INTERVAL 50 /* 50ms */
#define XD_FREE_TABLE_CNT 1200
#define MS_FREE_TABLE_CNT 512
/* Bit Operation */
#define SET_BIT(data, idx) ((data) |= 1 << (idx))
#define CLR_BIT(data, idx) ((data) &= ~(1 << (idx)))
#define CHK_BIT(data, idx) ((data) & (1 << (idx)))
/* Command type */
#define READ_REG_CMD 0
#define WRITE_REG_CMD 1
#define CHECK_REG_CMD 2
#define PACKET_TYPE 4
#define CNT_H 5
#define CNT_L 6
#define STAGE_FLAG 7
#define CMD_OFFSET 8
/* Packet type */
#define BATCH_CMD 0
#define SEQ_READ 1
#define SEQ_WRITE 2
/* Stage flag */
#define STAGE_R 0x01
#define STAGE_DI 0x02
#define STAGE_DO 0x04
/* Return MS_TRANS_CFG, GET_INT */
#define STAGE_MS_STATUS 0x08
/* Return XD_CFG, XD_CTL, XD_PAGE_STATUS */
#define STAGE_XD_STATUS 0x10
/* Command stage mode */
#define MODE_C 0x00
#define MODE_CR (STAGE_R)
#define MODE_CDIR (STAGE_R | STAGE_DI)
#define MODE_CDOR (STAGE_R | STAGE_DO)
/* Function return code */
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS 0
#endif
#define STATUS_FAIL 1
#define STATUS_READ_FAIL 2
#define STATUS_WRITE_FAIL 3
#define STATUS_TIMEDOUT 4
#define STATUS_NOMEM 5
#define STATUS_TRANS_SHORT 6
#define STATUS_TRANS_LONG 7
#define STATUS_STALLED 8
#define STATUS_ERROR 10
#define IDLE_MAX_COUNT 10
#define POLLING_WAIT_CNT 1
#define DELINK_DELAY 100
#define LED_TOGGLE_INTERVAL 6
#define LED_GPIO 0
/* package */
#define QFN24 0
#define LQFP48 1
#define USB_11 0
#define USB_20 1
/*
* Transport return codes
*/
/* Transport good, command good */
#define TRANSPORT_GOOD 0
/* Transport good, command failed */
#define TRANSPORT_FAILED 1
/* Command failed, no auto-sense */
#define TRANSPORT_NO_SENSE 2
/* Transport bad (i.e. device dead) */
#define TRANSPORT_ERROR 3
/* Supported Clock */
enum card_clock { CLK_20 = 1, CLK_30, CLK_40, CLK_50, CLK_60, CLK_80, CLK_100 };
#ifdef _MSG_TRACE
#define TRACE_ITEM_CNT 64
struct trace_msg_t {
u16 line;
#define MSG_FUNC_LEN 64
char func[MSG_FUNC_LEN];
#define MSG_FILE_LEN 32
char file[MSG_FILE_LEN];
#define TIME_VAL_LEN 16
u8 timeval_buf[TIME_VAL_LEN];
u8 valid;
};
#endif /* _MSG_TRACE */
/* Size of the autosense data buffer */
#define SENSE_SIZE 18
/* Sense type */
#define SENSE_TYPE_NO_SENSE 0
#define SENSE_TYPE_MEDIA_CHANGE 1
#define SENSE_TYPE_MEDIA_NOT_PRESENT 2
#define SENSE_TYPE_MEDIA_LBA_OVER_RANGE 3
#define SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT 4
#define SENSE_TYPE_MEDIA_WRITE_PROTECT 5
#define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6
#define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7
#define SENSE_TYPE_MEDIA_WRITE_ERR 8
#define SENSE_TYPE_FORMAT_IN_PROGRESS 9
#define SENSE_TYPE_FORMAT_CMD_FAILED 10
#ifdef SUPPORT_MAGIC_GATE
/* COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED */
#define SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB 0x0b
/* COPY PROTECTION KEY EXCHANGE FAILURE - AUTHENTICATION FAILURE */
#define SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN 0x0c
/* INCOMPATIBLE MEDIUM INSTALLED */
#define SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM 0x0d
/* WRITE ERROR */
#define SENSE_TYPE_MG_WRITE_ERR 0x0e
#endif
#ifdef SUPPORT_SD_LOCK
/* FOR Locked SD card */
#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10
#endif
/*---- sense key ----*/
#define ILI 0x20 /* ILI bit is on */
#define NO_SENSE 0x00 /* not exist sense key */
#define RECOVER_ERR 0x01 /* Target/Logical unit is recoverd */
#define NOT_READY 0x02 /* Logical unit is not ready */
#define MEDIA_ERR 0x03 /* medium/data error */
#define HARDWARE_ERR 0x04 /* hardware error */
#define ILGAL_REQ 0x05 /* CDB/parameter/identify msg error */
#define UNIT_ATTENTION 0x06 /* unit attention condition occur */
#define DAT_PRTCT 0x07 /* read/write is desable */
#define BLNC_CHK 0x08 /* find blank/DOF in read */
/* write to unblank area */
#define CPY_ABRT 0x0a /* Copy/Compare/Copy&Verify illgal */
#define ABRT_CMD 0x0b /* Target make the command in error */
#define EQUAL 0x0c /* Search Data end with Equal */
#define VLM_OVRFLW 0x0d /* Some data are left in buffer */
#define MISCMP 0x0e /* find inequality */
/*-----------------------------------
SENSE_DATA
-----------------------------------*/
/*---- valid ----*/
#define SENSE_VALID 0x80 /* Sense data is valid as SCSI2 */
#define SENSE_INVALID 0x00 /* Sense data is invalid as SCSI2 */
/*---- error code ----*/
#define CUR_ERR 0x70 /* current error */
#define DEF_ERR 0x71 /* specific command error */
/*---- sense key Infomation ----*/
#define SNSKEYINFO_LEN 3 /* length of sense key infomation */
#define SKSV 0x80
#define CDB_ILLEGAL 0x40
#define DAT_ILLEGAL 0x00
#define BPV 0x08
#define BIT_ILLEGAL0 0 /* bit0 is illegal */
#define BIT_ILLEGAL1 1 /* bit1 is illegal */
#define BIT_ILLEGAL2 2 /* bit2 is illegal */
#define BIT_ILLEGAL3 3 /* bit3 is illegal */
#define BIT_ILLEGAL4 4 /* bit4 is illegal */
#define BIT_ILLEGAL5 5 /* bit5 is illegal */
#define BIT_ILLEGAL6 6 /* bit6 is illegal */
#define BIT_ILLEGAL7 7 /* bit7 is illegal */
/*---- ASC ----*/
#define ASC_NO_INFO 0x00
#define ASC_MISCMP 0x1d
#define ASC_INVLD_CDB 0x24
#define ASC_INVLD_PARA 0x26
#define ASC_LU_NOT_READY 0x04
#define ASC_WRITE_ERR 0x0c
#define ASC_READ_ERR 0x11
#define ASC_LOAD_EJCT_ERR 0x53
#define ASC_MEDIA_NOT_PRESENT 0x3A
#define ASC_MEDIA_CHANGED 0x28
#define ASC_MEDIA_IN_PROCESS 0x04
#define ASC_WRITE_PROTECT 0x27
#define ASC_LUN_NOT_SUPPORTED 0x25
/*---- ASQC ----*/
#define ASCQ_NO_INFO 0x00
#define ASCQ_MEDIA_IN_PROCESS 0x01
#define ASCQ_MISCMP 0x00
#define ASCQ_INVLD_CDB 0x00
#define ASCQ_INVLD_PARA 0x02
#define ASCQ_LU_NOT_READY 0x02
#define ASCQ_WRITE_ERR 0x02
#define ASCQ_READ_ERR 0x00
#define ASCQ_LOAD_EJCT_ERR 0x00
#define ASCQ_WRITE_PROTECT 0x00
struct sense_data_t {
unsigned char err_code; /* error code */
/* bit7 : valid */
/* (1 : SCSI2) */
/* (0 : Vendor specific) */
/* bit6-0 : error code */
/* (0x70 : current error) */
/* (0x71 : specific command error) */
unsigned char seg_no; /* segment No. */
unsigned char sense_key; /* byte5 : ILI */
/* bit3-0 : sense key */
unsigned char info[4]; /* infomation */
unsigned char ad_sense_len; /* additional sense data length */
unsigned char cmd_info[4]; /* command specific infomation */
unsigned char asc; /* ASC */
unsigned char ascq; /* ASCQ */
unsigned char rfu; /* FRU */
unsigned char sns_key_info[3]; /* sense key specific infomation */
};
/* sd_ctl bit map */
/* SD push point control, bit 0, 1 */
#define SD_PUSH_POINT_CTL_MASK 0x03
#define SD_PUSH_POINT_DELAY 0x01
#define SD_PUSH_POINT_AUTO 0x02
/* SD sample point control, bit 2, 3 */
#define SD_SAMPLE_POINT_CTL_MASK 0x0C
#define SD_SAMPLE_POINT_DELAY 0x04
#define SD_SAMPLE_POINT_AUTO 0x08
/* SD DDR Tx phase set by user, bit 4 */
#define SD_DDR_TX_PHASE_SET_BY_USER 0x10
/* MMC DDR Tx phase set by user, bit 5 */
#define MMC_DDR_TX_PHASE_SET_BY_USER 0x20
/* Support MMC DDR mode, bit 6 */
/*#define SUPPORT_MMC_DDR_MODE 0x40 */
#define SUPPORT_UHS50_MMC44 0x40
struct rts51x_option {
u8 led_blink_speed;
int mspro_formatter_enable;
/* card clock expected by user for fpga platform */
int fpga_sd_sdr104_clk;
int fpga_sd_ddr50_clk;
int fpga_sd_sdr50_clk;
int fpga_sd_hs_clk;
int fpga_mmc_52m_clk;
int fpga_ms_hg_clk;
int fpga_ms_4bit_clk;
/* card clock expected by user for asic platform */
int asic_sd_sdr104_clk;
int asic_sd_ddr50_clk;
int asic_sd_sdr50_clk;
int asic_sd_hs_clk;
int asic_mmc_52m_clk;
int asic_ms_hg_clk;
int asic_ms_4bit_clk;
u8 ssc_depth_sd_sdr104; /* sw */
u8 ssc_depth_sd_ddr50; /* sw */
u8 ssc_depth_sd_sdr50; /* sw */
u8 ssc_depth_sd_hs; /* sw */
u8 ssc_depth_mmc_52m; /* sw */
u8 ssc_depth_ms_hg; /* sw */
u8 ssc_depth_ms_4bit; /* sw */
u8 ssc_depth_low_speed; /* sw */
/* SD/MMC Tx phase */
int sd_ddr_tx_phase; /* Enabled by bit 4 of sd_ctl */
int mmc_ddr_tx_phase; /* Enabled by bit 5 of sd_ctl */
/* priority of choosing sd speed funciton */
u32 sd_speed_prior;
/* sd card control */
u32 sd_ctl;
/* Enable Selective Suspend */
int ss_en;
/* Interval to enter SS from IDLE state (second) */
int ss_delay;
int needs_remote_wakeup;
u8 ww_enable; /* sangdy2010-08-03:add for remote wakeup */
/* Enable SSC clock */
int ssc_en;
int auto_delink_en;
/* sangdy2010-07-13:add FT2 fast mode */
int FT2_fast_mode;
/* sangdy2010-07-15:
* add for config delay between 1/4 PMOS and 3/4 PMOS */
int pwr_delay;
int xd_rw_step; /* add to tune xd tRP */
int D3318_off_delay; /* add to tune D3318 off delay time */
int delink_delay; /* add to tune delink delay time */
/* add for rts5129 to enable/disable D3318 off */
u8 rts5129_D3318_off_enable;
u8 sd20_pad_drive; /* add to config SD20 PAD drive */
u8 sd30_pad_drive; /* add to config SD30 pad drive */
/*if reset or rw fail,then set SD20 pad drive again */
u8 reset_or_rw_fail_set_pad_drive;
u8 rcc_fail_flag; /* add to indicate whether rcc bug happen */
u8 rcc_bug_fix_en; /* if set,then support fixing rcc bug */
u8 debounce_num; /* debounce number */
int polling_time; /* polling delay time */
u8 led_toggle_interval; /* used to control led toggle speed */
int xd_rwn_step;
u8 sd_send_status_en;
/* used to store default phase which is
* used when phase tune all pass. */
u8 ddr50_tx_phase;
u8 ddr50_rx_phase;
u8 sdr50_tx_phase;
u8 sdr50_rx_phase;
/* used to enable select sdr50 tx phase according to proportion. */
u8 sdr50_phase_sel;
u8 ms_errreg_fix;
u8 reset_mmc_first;
u8 speed_mmc; /* when set, then try CMD55 only twice */
u8 led_always_on; /* if set, then led always on when card exist */
u8 dv18_voltage; /* add to tune dv18 voltage */
};
#define MS_FORMATTER_ENABLED(chip) ((chip)->option.mspro_formatter_enable)
struct rts51x_chip;
typedef int (*card_rw_func) (struct scsi_cmnd *srb, struct rts51x_chip *chip,
u32 sec_addr, u16 sec_cnt);
/* For MS Card */
#define MAX_DEFECTIVE_BLOCK 10
struct zone_entry {
u16 *l2p_table;
u16 *free_table;
u16 defect_list[MAX_DEFECTIVE_BLOCK]; /* For MS card only */
int set_index;
int get_index;
int unused_blk_cnt;
int disable_count;
/* To indicate whether the L2P table of this zone has been built. */
int build_flag;
};
struct xd_delay_write_tag {
u32 old_phyblock;
u32 new_phyblock;
u32 logblock;
u8 pageoff;
u8 delay_write_flag;
};
struct xd_info {
u8 maker_code;
u8 device_code;
u8 block_shift;
u8 page_off;
u8 addr_cycle;
u16 cis_block;
u8 multi_flag;
u8 err_code;
u32 capacity;
struct zone_entry *zone;
int zone_cnt;
struct xd_delay_write_tag delay_write;
int counter;
int xd_clock;
};
#define TYPE_SD 0x0000
#define TYPE_MMC 0x0001
/* TYPE_SD */
#define SD_HS 0x0100
#define SD_SDR50 0x0200
#define SD_DDR50 0x0400
#define SD_SDR104 0x0800
#define SD_HCXC 0x1000
/* TYPE_MMC */
#define MMC_26M 0x0100
#define MMC_52M 0x0200
#define MMC_4BIT 0x0400
#define MMC_8BIT 0x0800
#define MMC_SECTOR_MODE 0x1000
#define MMC_DDR52 0x2000
/* SD card */
#define CHK_SD(sd_card) (((sd_card)->sd_type & 0xFF) == TYPE_SD)
#define CHK_SD_HS(sd_card) \
(CHK_SD(sd_card) && ((sd_card)->sd_type & SD_HS))
#define CHK_SD_SDR50(sd_card) \
(CHK_SD(sd_card) && ((sd_card)->sd_type & SD_SDR50))
#define CHK_SD_DDR50(sd_card) \
(CHK_SD(sd_card) && ((sd_card)->sd_type & SD_DDR50))
#define CHK_SD_SDR104(sd_card) \
(CHK_SD(sd_card) && ((sd_card)->sd_type & SD_SDR104))
#define CHK_SD_HCXC(sd_card) \
(CHK_SD(sd_card) && ((sd_card)->sd_type & SD_HCXC))
#define CHK_SD30_SPEED(sd_card) \
(CHK_SD_SDR50(sd_card) || CHK_SD_DDR50(sd_card) ||\
CHK_SD_SDR104(sd_card))
#define SET_SD(sd_card) ((sd_card)->sd_type = TYPE_SD)
#define SET_SD_HS(sd_card) ((sd_card)->sd_type |= SD_HS)
#define SET_SD_SDR50(sd_card) ((sd_card)->sd_type |= SD_SDR50)
#define SET_SD_DDR50(sd_card) ((sd_card)->sd_type |= SD_DDR50)
#define SET_SD_SDR104(sd_card) ((sd_card)->sd_type |= SD_SDR104)
#define SET_SD_HCXC(sd_card) ((sd_card)->sd_type |= SD_HCXC)
#define CLR_SD_HS(sd_card) ((sd_card)->sd_type &= ~SD_HS)
#define CLR_SD_SDR50(sd_card) ((sd_card)->sd_type &= ~SD_SDR50)
#define CLR_SD_DDR50(sd_card) ((sd_card)->sd_type &= ~SD_DDR50)
#define CLR_SD_SDR104(sd_card) ((sd_card)->sd_type &= ~SD_SDR104)
#define CLR_SD_HCXC(sd_card) ((sd_card)->sd_type &= ~SD_HCXC)
#define CLR_SD30_SPEED(sd_card) \
((sd_card)->sd_type &= ~(SD_SDR50|SD_DDR50|SD_SDR104))
/* MMC card */
#define CHK_MMC(sd_card) \
(((sd_card)->sd_type & 0xFF) == TYPE_MMC)
#define CHK_MMC_26M(sd_card) \
(CHK_MMC(sd_card) && ((sd_card)->sd_type & MMC_26M))
#define CHK_MMC_52M(sd_card) \
(CHK_MMC(sd_card) && ((sd_card)->sd_type & MMC_52M))
#define CHK_MMC_4BIT(sd_card) \
(CHK_MMC(sd_card) && ((sd_card)->sd_type & MMC_4BIT))
#define CHK_MMC_8BIT(sd_card) \
(CHK_MMC(sd_card) && ((sd_card)->sd_type & MMC_8BIT))
#define CHK_MMC_SECTOR_MODE(sd_card)\
(CHK_MMC(sd_card) && ((sd_card)->sd_type & MMC_SECTOR_MODE))
#define CHK_MMC_DDR52(sd_card) \
(CHK_MMC(sd_card) && ((sd_card)->sd_type & MMC_DDR52))
#define SET_MMC(sd_card) ((sd_card)->sd_type = TYPE_MMC)
#define SET_MMC_26M(sd_card) ((sd_card)->sd_type |= MMC_26M)
#define SET_MMC_52M(sd_card) ((sd_card)->sd_type |= MMC_52M)
#define SET_MMC_4BIT(sd_card) ((sd_card)->sd_type |= MMC_4BIT)
#define SET_MMC_8BIT(sd_card) ((sd_card)->sd_type |= MMC_8BIT)
#define SET_MMC_SECTOR_MODE(sd_card) ((sd_card)->sd_type |= MMC_SECTOR_MODE)
#define SET_MMC_DDR52(sd_card) ((sd_card)->sd_type |= MMC_DDR52)
#define CLR_MMC_26M(sd_card) ((sd_card)->sd_type &= ~MMC_26M)
#define CLR_MMC_52M(sd_card) ((sd_card)->sd_type &= ~MMC_52M)
#define CLR_MMC_4BIT(sd_card) ((sd_card)->sd_type &= ~MMC_4BIT)
#define CLR_MMC_8BIT(sd_card) ((sd_card)->sd_type &= ~MMC_8BIT)
#define CLR_MMC_SECTOR_MODE(sd_card) ((sd_card)->sd_type &= ~MMC_SECTOR_MODE)
#define CLR_MMC_DDR52(sd_card) ((sd_card)->sd_type &= ~MMC_DDR52)
#define CHK_MMC_HS(sd_card) \
(CHK_MMC_52M(sd_card) && CHK_MMC_26M(sd_card))
#define CLR_MMC_HS(sd_card) \
do { \
CLR_MMC_DDR52(sd_card); \
CLR_MMC_52M(sd_card); \
CLR_MMC_26M(sd_card); \
} while (0)
#define SD_SUPPORT_CLASS_TEN 0x01
#define SD_SUPPORT_1V8 0x02
#define SD_SET_CLASS_TEN(sd_card) \
((sd_card)->sd_setting |= SD_SUPPORT_CLASS_TEN)
#define SD_CHK_CLASS_TEN(sd_card) \
((sd_card)->sd_setting & SD_SUPPORT_CLASS_TEN)
#define SD_CLR_CLASS_TEN(sd_card) \
((sd_card)->sd_setting &= ~SD_SUPPORT_CLASS_TEN)
#define SD_SET_1V8(sd_card) \
((sd_card)->sd_setting |= SD_SUPPORT_1V8)
#define SD_CHK_1V8(sd_card) \
((sd_card)->sd_setting & SD_SUPPORT_1V8)
#define SD_CLR_1V8(sd_card) \
((sd_card)->sd_setting &= ~SD_SUPPORT_1V8)
#define CLR_RETRY_SD20_MODE(sd_card) \
((sd_card)->retry_SD20_mode = 0)
#define SET_RETRY_SD20_MODE(sd_card) \
((sd_card)->retry_SD20_mode = 1)
#define CHK_RETRY_SD20_MODE(sd_card) \
((sd_card)->retry_SD20_mode == 1)
struct sd_info {
u16 sd_type;
u8 err_code;
u8 sd_data_buf_ready;
u32 sd_addr;
u32 capacity;
u8 raw_csd[16];
u8 raw_scr[8];
/* Sequential RW */
int seq_mode;
enum dma_data_direction pre_dir;
u32 pre_sec_addr;
u16 pre_sec_cnt;
int counter;
int sd_clock;
#ifdef SUPPORT_CPRM
int sd_pass_thru_en;
int pre_cmd_err;
u8 last_rsp_type;
u8 rsp[17];
#endif
u8 func_group1_mask;
u8 func_group2_mask;
u8 func_group3_mask;
u8 func_group4_mask;
u8 sd_switch_fail;
u8 sd_read_phase;
u8 retry_SD20_mode; /* sangdy2010-06-10 */
u8 sd_reset_fail; /* sangdy2010-07-01 */
u8 sd_send_status_en;
#ifdef SUPPORT_SD_LOCK
u8 sd_lock_status;
u8 sd_erase_status;
u8 sd_lock_notify;
#endif
};
#define MODE_512_SEQ 0x01
#define MODE_2K_SEQ 0x02
#define TYPE_MS 0x0000
#define TYPE_MSPRO 0x0001
#define MS_4BIT 0x0100
#define MS_8BIT 0x0200
#define MS_HG 0x0400
#define MS_XC 0x0800
#define HG8BIT (MS_HG | MS_8BIT)
#define CHK_MSPRO(ms_card) \
(((ms_card)->ms_type & 0xFF) == TYPE_MSPRO)
#define CHK_HG8BIT(ms_card) \
(CHK_MSPRO(ms_card) && (((ms_card)->ms_type & HG8BIT) == HG8BIT))
#define CHK_MSXC(ms_card) \
(CHK_MSPRO(ms_card) && ((ms_card)->ms_type & MS_XC))
#define CHK_MSHG(ms_card) \
(CHK_MSPRO(ms_card) && ((ms_card)->ms_type & MS_HG))
#define CHK_MS8BIT(ms_card) (((ms_card)->ms_type & MS_8BIT))
#define CHK_MS4BIT(ms_card) (((ms_card)->ms_type & MS_4BIT))
struct ms_delay_write_tag {
u16 old_phyblock;
u16 new_phyblock;
u16 logblock;
u8 pageoff;
u8 delay_write_flag;
};
struct ms_info {
u16 ms_type;
u8 block_shift;
u8 page_off;
u16 total_block;
u16 boot_block;
u32 capacity;
u8 check_ms_flow;
u8 switch_8bit_fail;
u8 err_code;
struct zone_entry *segment;
int segment_cnt;
int pro_under_formatting;
int format_status;
u16 progress;
u8 raw_sys_info[96];
#ifdef SUPPORT_PCGL_1P18
u8 raw_model_name[48];
#endif
u8 multi_flag;
/* Sequential RW */
u8 seq_mode;
enum dma_data_direction pre_dir;
u32 pre_sec_addr;
u16 pre_sec_cnt;
u32 total_sec_cnt;
u8 last_rw_int;
struct ms_delay_write_tag delay_write;
int counter;
int ms_clock;
#ifdef SUPPORT_MAGIC_GATE
u8 magic_gate_id[16];
u8 mg_entry_num;
int mg_auth; /* flag to indicate authentication process */
#endif
};
#define PRO_UNDER_FORMATTING(ms_card) \
((ms_card)->pro_under_formatting)
#define SET_FORMAT_STATUS(ms_card, status) \
((ms_card)->format_status = (status))
#define CHK_FORMAT_STATUS(ms_card, status) \
((ms_card)->format_status == (status))
struct scsi_cmnd;
enum CHIP_STAT { STAT_INIT, STAT_IDLE, STAT_RUN, STAT_SS_PRE, STAT_SS,
STAT_SUSPEND };
struct rts51x_chip {
u16 vendor_id;
u16 product_id;
char max_lun;
struct scsi_cmnd *srb;
struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT];
#ifndef LED_AUTO_BLINK
int led_toggle_counter;
#endif
int ss_counter;
int idle_counter;
int auto_delink_counter;
enum CHIP_STAT chip_stat;
int resume_from_scsi;
/* Card information */
struct xd_info xd_card;
struct sd_info sd_card;
struct ms_info ms_card;
int cur_clk; /* current card clock */
int cur_card; /* Current card module */
u8 card_exist; /* card exist bit map (physical exist) */
u8 card_ready; /* card ready bit map (reset successfully) */
u8 card_fail; /* card reset fail bit map */
u8 card_ejected; /* card ejected bit map */
u8 card_wp; /* card write protected bit map */
u8 fake_card_ready;
/* flag to indicate whether to answer MediaChange */
unsigned long lun_mc;
/* card bus width */
u8 card_bus_width[MAX_ALLOWED_LUN_CNT];
/* card capacity */
u32 capacity[MAX_ALLOWED_LUN_CNT];
/* read/write card function pointer */
card_rw_func rw_card[MAX_ALLOWED_LUN_CNT];
/* read/write capacity, used for GPIO Toggle */
u32 rw_cap[MAX_ALLOWED_LUN_CNT];
/* card to lun mapping table */
u8 card2lun[32];
/* lun to card mapping table */
u8 lun2card[MAX_ALLOWED_LUN_CNT];
#ifdef _MSG_TRACE
struct trace_msg_t trace_msg[TRACE_ITEM_CNT];
int msg_idx;
#endif
int rw_need_retry;
/* ASIC or FPGA */
int asic_code;
/* QFN24 or LQFP48 */
int package;
/* Full Speed or High Speed */
int usb_speed;
/*sangdy:enable or disable UHS50 and MMC4.4 */
int uhs50_mmc44_en;
u8 ic_version;
/* Command buffer */
u8 *cmd_buf;
unsigned int cmd_idx;
/* Response buffer */
u8 *rsp_buf;
u16 card_status;
#ifdef SUPPORT_OCP
u16 ocp_stat;
#endif
struct rts51x_option option;
struct rts51x_usb *usb;
u8 rcc_read_response;
int reset_need_retry;
u8 rts5179;
};
#define UHS50_EN 0x0001
#define UHS50_DIS 0x0000
#define SET_UHS50(chip) ((chip)->uhs50_mmc44_en = UHS50_EN)
#define CLEAR_UHS50(chip) ((chip)->uhs50_mmc44_en = UHS50_DIS)
#define CHECK_UHS50(chip) (((chip)->uhs50_mmc44_en&0xff) == UHS50_EN)
#define RTS51X_GET_VID(chip) ((chip)->vendor_id)
#define RTS51X_GET_PID(chip) ((chip)->product_id)
#define RTS51X_SET_STAT(chip, stat) \
do { \
if ((stat) != STAT_IDLE) { \
(chip)->idle_counter = 0; \
} \
(chip)->chip_stat = (enum CHIP_STAT)(stat); \
} while (0)
#define RTS51X_CHK_STAT(chip, stat) ((chip)->chip_stat == (stat))
#define RTS51X_GET_STAT(chip) ((chip)->chip_stat)
#define CHECK_PID(chip, pid) (RTS51X_GET_PID(chip) == (pid))
#define CHECK_PKG(chip, pkg) ((chip)->package == (pkg))
#define CHECK_USB(chip, speed) ((chip)->usb_speed == (speed))
int rts51x_reset_chip(struct rts51x_chip *chip);
int rts51x_init_chip(struct rts51x_chip *chip);
int rts51x_release_chip(struct rts51x_chip *chip);
void rts51x_polling_func(struct rts51x_chip *chip);
static inline void rts51x_init_cmd(struct rts51x_chip *chip)
{
chip->cmd_idx = 0;
chip->cmd_buf[0] = 'R';
chip->cmd_buf[1] = 'T';
chip->cmd_buf[2] = 'C';
chip->cmd_buf[3] = 'R';
chip->cmd_buf[PACKET_TYPE] = BATCH_CMD;
}
void rts51x_add_cmd(struct rts51x_chip *chip,
u8 cmd_type, u16 reg_addr, u8 mask, u8 data);
int rts51x_send_cmd(struct rts51x_chip *chip, u8 flag, int timeout);
int rts51x_get_rsp(struct rts51x_chip *chip, int rsp_len, int timeout);
static inline void rts51x_read_rsp_buf(struct rts51x_chip *chip, int offset,
u8 *buf, int buf_len)
{
memcpy(buf, chip->rsp_buf + offset, buf_len);
}
static inline u8 *rts51x_get_rsp_data(struct rts51x_chip *chip)
{
return chip->rsp_buf;
}
int rts51x_get_card_status(struct rts51x_chip *chip, u16 * status);
int rts51x_write_register(struct rts51x_chip *chip, u16 addr, u8 mask, u8 data);
int rts51x_read_register(struct rts51x_chip *chip, u16 addr, u8 * data);
int rts51x_ep0_write_register(struct rts51x_chip *chip, u16 addr, u8 mask,
u8 data);
int rts51x_ep0_read_register(struct rts51x_chip *chip, u16 addr, u8 * data);
int rts51x_seq_write_register(struct rts51x_chip *chip, u16 addr, u16 len,
u8 *data);
int rts51x_seq_read_register(struct rts51x_chip *chip, u16 addr, u16 len,
u8 *data);
int rts51x_read_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len);
int rts51x_write_ppbuf(struct rts51x_chip *chip, u8 *buf, int buf_len);
int rts51x_write_phy_register(struct rts51x_chip *chip, u8 addr, u8 val);
int rts51x_read_phy_register(struct rts51x_chip *chip, u8 addr, u8 *val);
void rts51x_do_before_power_down(struct rts51x_chip *chip);
void rts51x_clear_hw_error(struct rts51x_chip *chip);
void rts51x_prepare_run(struct rts51x_chip *chip);
void rts51x_trace_msg(struct rts51x_chip *chip, unsigned char *buf, int clear);
void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
u8 status_len);
void rts51x_read_status(struct rts51x_chip *chip, unsigned int lun,
u8 *rts51x_status, u8 status_len);
int rts51x_transfer_data_rcc(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int len, int use_sg,
unsigned int *act_len, int timeout, u8 stage_flag);
#define RTS51X_WRITE_REG(chip, addr, mask, data) \
do { \
int _retval = rts51x_write_register((chip), \
(addr), (mask), (data)); \
if (_retval != STATUS_SUCCESS) { \
TRACE_RET((chip), _retval); \
} \
} while (0)
#define RTS51X_READ_REG(chip, addr, data) \
do { \
int _retval = rts51x_read_register((chip), \
(addr), (data)); \
if (_retval != STATUS_SUCCESS) { \
TRACE_RET((chip), _retval); \
} \
} while (0)
#endif /* __RTS51X_CHIP_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#include "rts51x.h"
#ifdef SUPPORT_FILE_OP
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/kref.h>
#include <linux/slab.h>
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_fop.h"
#include "sd_cprm.h"
#include "rts51x.h"
#define RTS5139_IOC_MAGIC 0x39
#define RTS5139_IOC_SD_DIRECT _IOWR(RTS5139_IOC_MAGIC, 0xA0, int)
#define RTS5139_IOC_SD_GET_RSP _IOWR(RTS5139_IOC_MAGIC, 0xA1, int)
static int rts51x_sd_direct_cmnd(struct rts51x_chip *chip,
struct sd_direct_cmnd *cmnd)
{
int retval;
u8 dir, cmd12, standby, acmd, cmd_idx, rsp_code;
u8 *buf;
u32 arg, len;
dir = (cmnd->cmnd[0] >> 3) & 0x03;
cmd12 = (cmnd->cmnd[0] >> 2) & 0x01;
standby = (cmnd->cmnd[0] >> 1) & 0x01;
acmd = cmnd->cmnd[0] & 0x01;
cmd_idx = cmnd->cmnd[1];
arg = ((u32) (cmnd->cmnd[2]) << 24) | ((u32) (cmnd->cmnd[3]) << 16) |
((u32) (cmnd->cmnd[4]) << 8) | cmnd->cmnd[5];
len =
((u32) (cmnd->cmnd[6]) << 16) | ((u32) (cmnd->cmnd[7]) << 8) |
cmnd->cmnd[8];
rsp_code = cmnd->cmnd[9];
if (dir) {
if (!cmnd->buf || (cmnd->buf_len < len))
TRACE_RET(chip, STATUS_FAIL);
}
switch (dir) {
case 0:
/* No data */
retval = ext_sd_execute_no_data(chip, chip->card2lun[SD_CARD],
cmd_idx, standby, acmd,
rsp_code, arg);
if (retval != TRANSPORT_GOOD)
TRACE_RET(chip, STATUS_FAIL);
break;
case 1:
/* Read from card */
buf = kmalloc(cmnd->buf_len, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, STATUS_NOMEM);
retval = ext_sd_execute_read_data(chip, chip->card2lun[SD_CARD],
cmd_idx, cmd12, standby, acmd,
rsp_code, arg, len, buf,
cmnd->buf_len, 0);
if (retval != TRANSPORT_GOOD) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
retval =
copy_to_user((void *)cmnd->buf, (void *)buf, cmnd->buf_len);
if (retval) {
kfree(buf);
TRACE_RET(chip, STATUS_NOMEM);
}
kfree(buf);
break;
case 2:
/* Write to card */
buf = kmalloc(cmnd->buf_len, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, STATUS_NOMEM);
retval =
copy_from_user((void *)buf, (void *)cmnd->buf,
cmnd->buf_len);
if (retval) {
kfree(buf);
TRACE_RET(chip, STATUS_NOMEM);
}
retval =
ext_sd_execute_write_data(chip, chip->card2lun[SD_CARD],
cmd_idx, cmd12, standby, acmd,
rsp_code, arg, len, buf,
cmnd->buf_len, 0);
if (retval != TRANSPORT_GOOD) {
kfree(buf);
TRACE_RET(chip, STATUS_FAIL);
}
kfree(buf);
break;
default:
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int rts51x_sd_get_rsp(struct rts51x_chip *chip, struct sd_rsp *rsp)
{
struct sd_info *sd_card = &(chip->sd_card);
int count = 0, retval;
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
TRACE_RET(chip, STATUS_FAIL);
}
if (sd_card->last_rsp_type == SD_RSP_TYPE_R0)
TRACE_RET(chip, STATUS_FAIL);
else if (sd_card->last_rsp_type == SD_RSP_TYPE_R2)
count = (rsp->rsp_len < 17) ? rsp->rsp_len : 17;
else
count = (rsp->rsp_len < 6) ? rsp->rsp_len : 6;
retval = copy_to_user((void *)rsp->rsp, (void *)sd_card->rsp, count);
if (retval)
TRACE_RET(chip, STATUS_NOMEM);
RTS51X_DEBUGP("Response length: %d\n", count);
RTS51X_DEBUGP("Response: 0x%x 0x%x 0x%x 0x%x\n",
sd_card->rsp[0], sd_card->rsp[1], sd_card->rsp[2],
sd_card->rsp[3]);
return STATUS_SUCCESS;
}
int rts51x_open(struct inode *inode, struct file *filp)
{
struct rts51x_chip *chip;
struct usb_interface *interface;
int subminor;
int retval = 0;
subminor = iminor(inode);
interface = usb_find_interface(&rts51x_driver, subminor);
if (!interface) {
RTS51X_DEBUGP("%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV;
goto exit;
}
chip = (struct rts51x_chip *)usb_get_intfdata(interface);
if (!chip) {
RTS51X_DEBUGP("Can't find chip\n");
retval = -ENODEV;
goto exit;
}
/* Increase our reference to the host */
scsi_host_get(rts51x_to_host(chip));
/* lock the device pointers */
mutex_lock(&(chip->usb->dev_mutex));
/* save our object in the file's private structure */
filp->private_data = chip;
/* unlock the device pointers */
mutex_unlock(&chip->usb->dev_mutex);
exit:
return retval;
}
int rts51x_release(struct inode *inode, struct file *filp)
{
struct rts51x_chip *chip;
chip = (struct rts51x_chip *)filp->private_data;
if (chip == NULL)
return -ENODEV;
/* Drop our reference to the host; the SCSI core will free it
* (and "chip" along with it) when the refcount becomes 0. */
scsi_host_put(rts51x_to_host(chip));
return 0;
}
ssize_t rts51x_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
return 0;
}
ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
return 0;
}
#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
#else
long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#endif
{
struct rts51x_chip *chip;
struct sd_direct_cmnd cmnd;
struct sd_rsp rsp;
int retval = 0;
chip = (struct rts51x_chip *)filp->private_data;
if (chip == NULL)
return -ENODEV;
/* lock the device pointers */
mutex_lock(&(chip->usb->dev_mutex));
switch (cmd) {
case RTS5139_IOC_SD_DIRECT:
retval =
copy_from_user((void *)&cmnd, (void *)arg,
sizeof(struct sd_direct_cmnd));
if (retval) {
retval = -ENOMEM;
TRACE_GOTO(chip, exit);
}
retval = rts51x_sd_direct_cmnd(chip, &cmnd);
if (retval != STATUS_SUCCESS) {
retval = -EIO;
TRACE_GOTO(chip, exit);
}
break;
case RTS5139_IOC_SD_GET_RSP:
retval =
copy_from_user((void *)&rsp, (void *)arg,
sizeof(struct sd_rsp));
if (retval) {
retval = -ENOMEM;
TRACE_GOTO(chip, exit);
}
retval = rts51x_sd_get_rsp(chip, &rsp);
if (retval != STATUS_SUCCESS) {
retval = -EIO;
TRACE_GOTO(chip, exit);
}
break;
default:
break;
}
exit:
/* unlock the device pointers */
mutex_unlock(&chip->usb->dev_mutex);
return retval;
}
#endif
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_FOP_H
#define __RTS51X_FOP_H
#include "rts51x.h"
#ifdef SUPPORT_FILE_OP
#include <linux/fs.h>
#include <linux/types.h>
struct sd_direct_cmnd {
u8 cmnd[12];
void *buf;
int buf_len;
};
struct sd_rsp {
void *rsp;
int rsp_len;
};
int rts51x_open(struct inode *inode, struct file *filp);
int rts51x_release(struct inode *inode, struct file *filp);
ssize_t rts51x_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos);
ssize_t rts51x_write(struct file *filp, const char __user * buf, size_t count,
loff_t *f_pos);
#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
#else
long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
#endif
#endif
#endif /* __RTS51X_FOP_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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 <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "debug.h"
#include "rts51x.h"
#include "rts51x_chip.h"
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
#include "rts51x_sys.h"
#include "sd_cprm.h"
#include "ms_mg.h"
#include "trace.h"
void scsi_show_command(struct scsi_cmnd *srb)
{
char *what = NULL;
int i, unknown_cmd = 0;
switch (srb->cmnd[0]) {
case TEST_UNIT_READY:
what = (char *)"TEST_UNIT_READY";
break;
case REZERO_UNIT:
what = (char *)"REZERO_UNIT";
break;
case REQUEST_SENSE:
what = (char *)"REQUEST_SENSE";
break;
case FORMAT_UNIT:
what = (char *)"FORMAT_UNIT";
break;
case READ_BLOCK_LIMITS:
what = (char *)"READ_BLOCK_LIMITS";
break;
case 0x07:
what = (char *)"REASSIGN_BLOCKS";
break;
case READ_6:
what = (char *)"READ_6";
break;
case WRITE_6:
what = (char *)"WRITE_6";
break;
case SEEK_6:
what = (char *)"SEEK_6";
break;
case READ_REVERSE:
what = (char *)"READ_REVERSE";
break;
case WRITE_FILEMARKS:
what = (char *)"WRITE_FILEMARKS";
break;
case SPACE:
what = (char *)"SPACE";
break;
case INQUIRY:
what = (char *)"INQUIRY";
break;
case RECOVER_BUFFERED_DATA:
what = (char *)"RECOVER_BUFFERED_DATA";
break;
case MODE_SELECT:
what = (char *)"MODE_SELECT";
break;
case RESERVE:
what = (char *)"RESERVE";
break;
case RELEASE:
what = (char *)"RELEASE";
break;
case COPY:
what = (char *)"COPY";
break;
case ERASE:
what = (char *)"ERASE";
break;
case MODE_SENSE:
what = (char *)"MODE_SENSE";
break;
case START_STOP:
what = (char *)"START_STOP";
break;
case RECEIVE_DIAGNOSTIC:
what = (char *)"RECEIVE_DIAGNOSTIC";
break;
case SEND_DIAGNOSTIC:
what = (char *)"SEND_DIAGNOSTIC";
break;
case ALLOW_MEDIUM_REMOVAL:
what = (char *)"ALLOW_MEDIUM_REMOVAL";
break;
case SET_WINDOW:
what = (char *)"SET_WINDOW";
break;
case READ_CAPACITY:
what = (char *)"READ_CAPACITY";
break;
case READ_10:
what = (char *)"READ_10";
break;
case WRITE_10:
what = (char *)"WRITE_10";
break;
case SEEK_10:
what = (char *)"SEEK_10";
break;
case WRITE_VERIFY:
what = (char *)"WRITE_VERIFY";
break;
case VERIFY:
what = (char *)"VERIFY";
break;
case SEARCH_HIGH:
what = (char *)"SEARCH_HIGH";
break;
case SEARCH_EQUAL:
what = (char *)"SEARCH_EQUAL";
break;
case SEARCH_LOW:
what = (char *)"SEARCH_LOW";
break;
case SET_LIMITS:
what = (char *)"SET_LIMITS";
break;
case READ_POSITION:
what = (char *)"READ_POSITION";
break;
case SYNCHRONIZE_CACHE:
what = (char *)"SYNCHRONIZE_CACHE";
break;
case LOCK_UNLOCK_CACHE:
what = (char *)"LOCK_UNLOCK_CACHE";
break;
case READ_DEFECT_DATA:
what = (char *)"READ_DEFECT_DATA";
break;
case MEDIUM_SCAN:
what = (char *)"MEDIUM_SCAN";
break;
case COMPARE:
what = (char *)"COMPARE";
break;
case COPY_VERIFY:
what = (char *)"COPY_VERIFY";
break;
case WRITE_BUFFER:
what = (char *)"WRITE_BUFFER";
break;
case READ_BUFFER:
what = (char *)"READ_BUFFER";
break;
case UPDATE_BLOCK:
what = (char *)"UPDATE_BLOCK";
break;
case READ_LONG:
what = (char *)"READ_LONG";
break;
case WRITE_LONG:
what = (char *)"WRITE_LONG";
break;
case CHANGE_DEFINITION:
what = (char *)"CHANGE_DEFINITION";
break;
case WRITE_SAME:
what = (char *)"WRITE_SAME";
break;
case GPCMD_READ_SUBCHANNEL:
what = (char *)"READ SUBCHANNEL";
break;
case READ_TOC:
what = (char *)"READ_TOC";
break;
case GPCMD_READ_HEADER:
what = (char *)"READ HEADER";
break;
case GPCMD_PLAY_AUDIO_10:
what = (char *)"PLAY AUDIO (10)";
break;
case GPCMD_PLAY_AUDIO_MSF:
what = (char *)"PLAY AUDIO MSF";
break;
case GPCMD_GET_EVENT_STATUS_NOTIFICATION:
what = (char *)"GET EVENT/STATUS NOTIFICATION";
break;
case GPCMD_PAUSE_RESUME:
what = (char *)"PAUSE/RESUME";
break;
case LOG_SELECT:
what = (char *)"LOG_SELECT";
break;
case LOG_SENSE:
what = (char *)"LOG_SENSE";
break;
case GPCMD_STOP_PLAY_SCAN:
what = (char *)"STOP PLAY/SCAN";
break;
case GPCMD_READ_DISC_INFO:
what = (char *)"READ DISC INFORMATION";
break;
case GPCMD_READ_TRACK_RZONE_INFO:
what = (char *)"READ TRACK INFORMATION";
break;
case GPCMD_RESERVE_RZONE_TRACK:
what = (char *)"RESERVE TRACK";
break;
case GPCMD_SEND_OPC:
what = (char *)"SEND OPC";
break;
case MODE_SELECT_10:
what = (char *)"MODE_SELECT_10";
break;
case GPCMD_REPAIR_RZONE_TRACK:
what = (char *)"REPAIR TRACK";
break;
case 0x59:
what = (char *)"READ MASTER CUE";
break;
case MODE_SENSE_10:
what = (char *)"MODE_SENSE_10";
break;
case GPCMD_CLOSE_TRACK:
what = (char *)"CLOSE TRACK/SESSION";
break;
case 0x5C:
what = (char *)"READ BUFFER CAPACITY";
break;
case 0x5D:
what = (char *)"SEND CUE SHEET";
break;
case GPCMD_BLANK:
what = (char *)"BLANK";
break;
case REPORT_LUNS:
what = (char *)"REPORT LUNS";
break;
case MOVE_MEDIUM:
what = (char *)"MOVE_MEDIUM or PLAY AUDIO (12)";
break;
case READ_12:
what = (char *)"READ_12";
break;
case WRITE_12:
what = (char *)"WRITE_12";
break;
case WRITE_VERIFY_12:
what = (char *)"WRITE_VERIFY_12";
break;
case SEARCH_HIGH_12:
what = (char *)"SEARCH_HIGH_12";
break;
case SEARCH_EQUAL_12:
what = (char *)"SEARCH_EQUAL_12";
break;
case SEARCH_LOW_12:
what = (char *)"SEARCH_LOW_12";
break;
case SEND_VOLUME_TAG:
what = (char *)"SEND_VOLUME_TAG";
break;
case READ_ELEMENT_STATUS:
what = (char *)"READ_ELEMENT_STATUS";
break;
case GPCMD_READ_CD_MSF:
what = (char *)"READ CD MSF";
break;
case GPCMD_SCAN:
what = (char *)"SCAN";
break;
case GPCMD_SET_SPEED:
what = (char *)"SET CD SPEED";
break;
case GPCMD_MECHANISM_STATUS:
what = (char *)"MECHANISM STATUS";
break;
case GPCMD_READ_CD:
what = (char *)"READ CD";
break;
case 0xE1:
what = (char *)"WRITE CONTINUE";
break;
case WRITE_LONG_2:
what = (char *)"WRITE_LONG_2";
break;
case VENDOR_CMND:
what = (char *)"Realtek's vendor command";
break;
default:
what = (char *)"(unknown command)";
unknown_cmd = 1;
break;
}
if (srb->cmnd[0] != TEST_UNIT_READY)
RTS51X_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len);
if (unknown_cmd) {
RTS51X_DEBUGP("");
for (i = 0; i < srb->cmd_len && i < 16; i++)
RTS51X_DEBUGPN(" %02x", srb->cmnd[i]);
RTS51X_DEBUGPN("\n");
}
}
void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type)
{
switch (sense_type) {
case SENSE_TYPE_MEDIA_CHANGE:
set_sense_data(chip, lun, CUR_ERR, 0x06, 0, 0x28, 0, 0, 0);
break;
case SENSE_TYPE_MEDIA_NOT_PRESENT:
set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x3A, 0, 0, 0);
break;
case SENSE_TYPE_MEDIA_LBA_OVER_RANGE:
set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x21, 0, 0, 0);
break;
case SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT:
set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x25, 0, 0, 0);
break;
case SENSE_TYPE_MEDIA_WRITE_PROTECT:
set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x27, 0, 0, 0);
break;
case SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR:
set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x11, 0, 0, 0);
break;
case SENSE_TYPE_MEDIA_WRITE_ERR:
set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x0C, 0x02, 0, 0);
break;
case SENSE_TYPE_MEDIA_INVALID_CMD_FIELD:
set_sense_data(chip, lun, CUR_ERR, ILGAL_REQ, 0,
ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1);
break;
case SENSE_TYPE_FORMAT_IN_PROGRESS:
set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0);
break;
case SENSE_TYPE_FORMAT_CMD_FAILED:
set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0);
break;
#ifdef SUPPORT_MAGIC_GATE
case SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB:
set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x6F, 0x02, 0, 0);
break;
case SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN:
set_sense_data(chip, lun, CUR_ERR, 0x05, 0, 0x6F, 0x00, 0, 0);
break;
case SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM:
set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x30, 0x00, 0, 0);
break;
case SENSE_TYPE_MG_WRITE_ERR:
set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x0C, 0x00, 0, 0);
break;
#endif
#ifdef SUPPORT_SD_LOCK
case SENSE_TYPE_MEDIA_READ_FORBIDDEN:
set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0);
break;
#endif
case SENSE_TYPE_NO_SENSE:
default:
set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0);
break;
}
}
void set_sense_data(struct rts51x_chip *chip, unsigned int lun, u8 err_code,
u8 sense_key, u32 info, u8 asc, u8 ascq, u8 sns_key_info0,
u16 sns_key_info1)
{
struct sense_data_t *sense = &(chip->sense_buffer[lun]);
sense->err_code = err_code;
sense->sense_key = sense_key;
sense->info[0] = (u8) (info >> 24);
sense->info[1] = (u8) (info >> 16);
sense->info[2] = (u8) (info >> 8);
sense->info[3] = (u8) info;
sense->ad_sense_len = sizeof(struct sense_data_t) - 8;
sense->asc = asc;
sense->ascq = ascq;
if (sns_key_info0 != 0) {
sense->sns_key_info[0] = SKSV | sns_key_info0;
sense->sns_key_info[1] = (sns_key_info1 & 0xf0) >> 8;
sense->sns_key_info[2] = sns_key_info1 & 0x0f;
}
}
static int test_unit_ready(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
rts51x_init_cards(chip);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
return TRANSPORT_FAILED;
}
if (!check_lun_mc(chip, lun)) {
set_lun_mc(chip, lun);
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
return TRANSPORT_FAILED;
}
#ifdef SUPPORT_SD_LOCK
if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) {
struct sd_info *sd_card = &(chip->sd_card);
if (sd_card->sd_lock_notify) {
sd_card->sd_lock_notify = 0;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
return TRANSPORT_FAILED;
} else if (sd_card->sd_lock_status & SD_LOCKED) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_READ_FORBIDDEN);
return TRANSPORT_FAILED;
}
}
#endif
return TRANSPORT_GOOD;
}
unsigned char formatter_inquiry_str[20] = {
'M', 'E', 'M', 'O', 'R', 'Y', 'S', 'T', 'I', 'C', 'K',
'-', 'M', 'G', /* Byte[47:49] */
0x0B, /* Byte[50]: MG, MS, MSPro, MSXC */
0x00, /* Byte[51]: Category Specific Commands */
0x00, /* Byte[52]: Access Control and feature */
0x20, 0x20, 0x20, /* Byte[53:55] */
};
static int inquiry(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
char *inquiry_default = (char *)"Generic-xD/SD/M.S. 1.00 ";
char *inquiry_string;
unsigned char sendbytes;
unsigned char *buf;
u8 card = get_lun_card(chip, lun);
int pro_formatter_flag = 0;
unsigned char inquiry_buf[] = {
QULIFIRE | DRCT_ACCESS_DEV,
RMB_DISC | 0x0D,
0x00,
0x01,
0x1f,
0x02,
0,
REL_ADR | WBUS_32 | WBUS_16 | SYNC | LINKED | CMD_QUE | SFT_RE,
};
inquiry_string = inquiry_default;
buf = vmalloc(scsi_bufflen(srb));
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
if (MS_FORMATTER_ENABLED(chip) && (get_lun2card(chip, lun) & MS_CARD)) {
if (!card || (card == MS_CARD))
pro_formatter_flag = 1;
}
if (pro_formatter_flag) {
if (scsi_bufflen(srb) < 56)
sendbytes = (unsigned char)(scsi_bufflen(srb));
else
sendbytes = 56;
} else {
if (scsi_bufflen(srb) < 36)
sendbytes = (unsigned char)(scsi_bufflen(srb));
else
sendbytes = 36;
}
if (sendbytes > 8) {
memcpy(buf, inquiry_buf, 8);
memcpy(buf + 8, inquiry_string, sendbytes - 8);
if (pro_formatter_flag)
buf[4] = 0x33; /* Additional Length */
} else {
memcpy(buf, inquiry_buf, sendbytes);
}
if (pro_formatter_flag) {
if (sendbytes > 36)
memcpy(buf + 36, formatter_inquiry_str, sendbytes - 36);
}
scsi_set_resid(srb, 0);
rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
vfree(buf);
return TRANSPORT_GOOD;
}
static int start_stop_unit(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
scsi_set_resid(srb, scsi_bufflen(srb));
if (srb->cmnd[1] == 1)
return TRANSPORT_GOOD;
switch (srb->cmnd[0x4]) {
case STOP_MEDIUM:
/* Media disabled */
return TRANSPORT_GOOD;
case UNLOAD_MEDIUM:
/* Media shall be unload */
if (check_card_ready(chip, lun))
eject_card(chip, lun);
return TRANSPORT_GOOD;
case MAKE_MEDIUM_READY:
case LOAD_MEDIUM:
if (check_card_ready(chip, lun)) {
return TRANSPORT_GOOD;
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
}
TRACE_RET(chip, TRANSPORT_ERROR);
}
static int allow_medium_removal(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int prevent;
prevent = srb->cmnd[4] & 0x1;
scsi_set_resid(srb, 0);
if (prevent) {
set_sense_type(chip, SCSI_LUN(srb),
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
return TRANSPORT_GOOD;
}
static void ms_mode_sense(struct rts51x_chip *chip, u8 cmd,
int lun, u8 *buf, int buf_len)
{
struct ms_info *ms_card = &(chip->ms_card);
int sys_info_offset;
int data_size = buf_len;
int support_format = 0;
int i = 0;
if (cmd == MODE_SENSE) {
sys_info_offset = 8;
if (data_size > 0x68)
data_size = 0x68;
buf[i++] = 0x67; /* Mode Data Length */
} else {
sys_info_offset = 12;
if (data_size > 0x6C)
data_size = 0x6C;
buf[i++] = 0x00; /* Mode Data Length (MSB) */
buf[i++] = 0x6A; /* Mode Data Length (LSB) */
}
/* Medium Type Code */
if (check_card_ready(chip, lun)) {
if (CHK_MSXC(ms_card)) {
support_format = 1;
buf[i++] = 0x40;
} else if (CHK_MSPRO(ms_card)) {
support_format = 1;
buf[i++] = 0x20;
} else {
buf[i++] = 0x10;
}
/* WP */
if (check_card_wp(chip, lun))
buf[i++] = 0x80;
else
buf[i++] = 0x00;
} else {
buf[i++] = 0x00; /* MediaType */
buf[i++] = 0x00; /* WP */
}
buf[i++] = 0x00; /* Reserved */
if (cmd == MODE_SENSE_10) {
buf[i++] = 0x00; /* Reserved */
buf[i++] = 0x00; /* Block descriptor length(MSB) */
buf[i++] = 0x00; /* Block descriptor length(LSB) */
/* The Following Data is the content of "Page 0x20" */
if (data_size >= 9)
buf[i++] = 0x20; /* Page Code */
if (data_size >= 10)
buf[i++] = 0x62; /* Page Length */
if (data_size >= 11)
buf[i++] = 0x00; /* No Access Control */
if (data_size >= 12) {
if (support_format)
buf[i++] = 0xC0; /* SF, SGM */
else
buf[i++] = 0x00;
}
} else {
/* The Following Data is the content of "Page 0x20" */
if (data_size >= 5)
buf[i++] = 0x20; /* Page Code */
if (data_size >= 6)
buf[i++] = 0x62; /* Page Length */
if (data_size >= 7)
buf[i++] = 0x00; /* No Access Control */
if (data_size >= 8) {
if (support_format)
buf[i++] = 0xC0; /* SF, SGM */
else
buf[i++] = 0x00;
}
}
if (data_size > sys_info_offset) {
/* 96 Bytes Attribute Data */
int len = data_size - sys_info_offset;
len = (len < 96) ? len : 96;
memcpy(buf + sys_info_offset, ms_card->raw_sys_info, len);
}
}
static int mode_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
unsigned int dataSize;
int status;
int pro_formatter_flag;
unsigned char pageCode, *buf;
u8 card = get_lun_card(chip, lun);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
scsi_set_resid(srb, scsi_bufflen(srb));
TRACE_RET(chip, TRANSPORT_FAILED);
}
pro_formatter_flag = 0;
dataSize = 8;
/* In Combo mode, device responses ModeSense command as a MS LUN
* when no card is inserted */
if ((get_lun2card(chip, lun) & MS_CARD)) {
if (!card || (card == MS_CARD)) {
dataSize = 108;
if (chip->option.mspro_formatter_enable)
pro_formatter_flag = 1;
}
}
buf = kmalloc(dataSize, GFP_KERNEL);
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
pageCode = srb->cmnd[2] & 0x3f;
if ((pageCode == 0x3F) || (pageCode == 0x1C) ||
(pageCode == 0x00) || (pro_formatter_flag && (pageCode == 0x20))) {
if (srb->cmnd[0] == MODE_SENSE) {
if ((pageCode == 0x3F) || (pageCode == 0x20)) {
ms_mode_sense(chip, srb->cmnd[0], lun, buf,
dataSize);
} else {
dataSize = 4;
buf[0] = 0x03;
buf[1] = 0x00;
if (check_card_wp(chip, lun))
buf[2] = 0x80;
else
buf[3] = 0x00;
}
} else {
if ((pageCode == 0x3F) || (pageCode == 0x20)) {
ms_mode_sense(chip, srb->cmnd[0], lun, buf,
dataSize);
} else {
dataSize = 8;
buf[0] = 0x00;
buf[1] = 0x06;
buf[2] = 0x00;
if (check_card_wp(chip, lun))
buf[3] = 0x80;
else
buf[3] = 0x00;
buf[4] = 0x00;
buf[5] = 0x00;
buf[6] = 0x00;
buf[7] = 0x00;
}
}
status = TRANSPORT_GOOD;
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
scsi_set_resid(srb, scsi_bufflen(srb));
status = TRANSPORT_FAILED;
}
if (status == TRANSPORT_GOOD) {
unsigned int len = min(scsi_bufflen(srb), dataSize);
rts51x_set_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
}
kfree(buf);
return status;
}
static int request_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sense_data_t *sense;
unsigned int lun = SCSI_LUN(srb);
struct ms_info *ms_card = &(chip->ms_card);
unsigned char *tmp, *buf;
sense = &(chip->sense_buffer[lun]);
if ((get_lun_card(chip, lun) == MS_CARD)
&& PRO_UNDER_FORMATTING(ms_card)) {
mspro_format_sense(chip, lun);
}
buf = vmalloc(scsi_bufflen(srb));
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
tmp = (unsigned char *)sense;
memcpy(buf, tmp, scsi_bufflen(srb));
rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
vfree(buf);
scsi_set_resid(srb, 0);
/* Reset Sense Data */
set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
return TRANSPORT_GOOD;
}
static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
#ifdef SUPPORT_SD_LOCK
struct sd_info *sd_card = &(chip->sd_card);
#endif
unsigned int lun = SCSI_LUN(srb);
int retval;
u32 start_sec;
u16 sec_cnt;
if (!check_card_ready(chip, lun) || (chip->capacity[lun] == 0)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (!check_lun_mc(chip, lun)) {
set_lun_mc(chip, lun);
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
return TRANSPORT_FAILED;
}
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
#ifdef SUPPORT_SD_LOCK
if (sd_card->sd_erase_status) {
/* Accessing to any card is forbidden
* until the erase procedure of SD is completed */
RTS51X_DEBUGP("SD card being erased!\n");
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (get_lun_card(chip, lun) == SD_CARD) {
if (sd_card->sd_lock_status & SD_LOCKED) {
RTS51X_DEBUGP("SD card locked!\n");
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_READ_FORBIDDEN);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
#endif
if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) {
start_sec =
((u32) srb->cmnd[2] << 24) |
((u32) srb->cmnd[3] << 16) |
((u32) srb->cmnd[4] << 8) |
((u32) srb->cmnd[5]);
sec_cnt = ((u16) (srb->cmnd[7]) << 8) | srb->cmnd[8];
} else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) {
start_sec = ((u32) (srb->cmnd[1] & 0x1F) << 16) |
((u32) srb->cmnd[2] << 8) | ((u32) srb->cmnd[3]);
sec_cnt = srb->cmnd[4];
} else if ((srb->cmnd[0] == VENDOR_CMND) &&
(srb->cmnd[1] == SCSI_APP_CMD) &&
((srb->cmnd[2] == PP_READ10) ||
(srb->cmnd[2] == PP_WRITE10))) {
start_sec = ((u32) srb->cmnd[4] << 24) |
((u32) srb->cmnd[5] << 16) |
((u32) srb->cmnd[6] << 8) |
((u32) srb->cmnd[7]);
sec_cnt = ((u16) (srb->cmnd[9]) << 8) | srb->cmnd[10];
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((start_sec > chip->capacity[lun]) ||
((start_sec + sec_cnt) > chip->capacity[lun])) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LBA_OVER_RANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (sec_cnt == 0) {
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
if ((srb->sc_data_direction == DMA_TO_DEVICE)
&& check_card_wp(chip, lun)) {
RTS51X_DEBUGP("Write protected card!\n");
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
retval = card_rw(srb, chip, start_sec, sec_cnt);
if (retval != STATUS_SUCCESS) {
#if 0
if (chip->need_release & chip->lun2card[lun]) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
} else {
#endif
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
}
#if 0
}
#endif
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
static int read_format_capacity(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned char *buf;
unsigned int lun = SCSI_LUN(srb);
unsigned int buf_len;
u8 card = get_lun_card(chip, lun);
int desc_cnt;
int i = 0;
if (!check_card_ready(chip, lun)) {
if (!chip->option.mspro_formatter_enable) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
buf_len = (scsi_bufflen(srb) > 12) ? 0x14 : 12;
buf = kmalloc(buf_len, GFP_KERNEL);
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
buf[i++] = 0;
buf[i++] = 0;
buf[i++] = 0;
/* Capacity List Length */
if ((buf_len > 12) && chip->option.mspro_formatter_enable &&
(chip->lun2card[lun] & MS_CARD) && (!card || (card == MS_CARD))) {
buf[i++] = 0x10;
desc_cnt = 2;
} else {
buf[i++] = 0x08;
desc_cnt = 1;
}
while (desc_cnt) {
if (check_card_ready(chip, lun)) {
buf[i++] = (unsigned char)((chip->capacity[lun]) >> 24);
buf[i++] = (unsigned char)((chip->capacity[lun]) >> 16);
buf[i++] = (unsigned char)((chip->capacity[lun]) >> 8);
buf[i++] = (unsigned char)(chip->capacity[lun]);
if (desc_cnt == 2)
/* Byte[8]: Descriptor Type: Formatted medium */
buf[i++] = 2;
else
buf[i++] = 0; /* Byte[16] */
} else {
buf[i++] = 0xFF;
buf[i++] = 0xFF;
buf[i++] = 0xFF;
buf[i++] = 0xFF;
if (desc_cnt == 2)
/* Byte[8]: Descriptor Type: No medium */
buf[i++] = 3;
else
buf[i++] = 0; /*Byte[16] */
}
buf[i++] = 0x00;
buf[i++] = 0x02;
buf[i++] = 0x00;
desc_cnt--;
}
buf_len = min(scsi_bufflen(srb), buf_len);
rts51x_set_xfer_buf(buf, buf_len, srb);
kfree(buf);
scsi_set_resid(srb, scsi_bufflen(srb) - buf_len);
return TRANSPORT_GOOD;
}
static int read_capacity(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned char *buf;
unsigned int lun = SCSI_LUN(srb);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (!check_lun_mc(chip, lun)) {
set_lun_mc(chip, lun);
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
return TRANSPORT_FAILED;
}
buf = kmalloc(8, GFP_KERNEL);
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
buf[0] = (unsigned char)((chip->capacity[lun] - 1) >> 24);
buf[1] = (unsigned char)((chip->capacity[lun] - 1) >> 16);
buf[2] = (unsigned char)((chip->capacity[lun] - 1) >> 8);
buf[3] = (unsigned char)(chip->capacity[lun] - 1);
buf[4] = 0x00;
buf[5] = 0x00;
buf[6] = 0x02;
buf[7] = 0x00;
rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
kfree(buf);
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
static int get_dev_status(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
unsigned int buf_len;
u8 status[32] = { 0 };
rts51x_pp_status(chip, lun, status, 32);
buf_len = min(scsi_bufflen(srb), (unsigned int)sizeof(status));
rts51x_set_xfer_buf(status, buf_len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - buf_len);
return TRANSPORT_GOOD;
}
static int read_status(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
u8 rts51x_status[16];
unsigned int buf_len;
unsigned int lun = SCSI_LUN(srb);
rts51x_read_status(chip, lun, rts51x_status, 16);
buf_len = min(scsi_bufflen(srb), (unsigned int)sizeof(rts51x_status));
rts51x_set_xfer_buf(rts51x_status, buf_len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - buf_len);
return TRANSPORT_GOOD;
}
static int read_mem(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
unsigned short addr, len, i;
int retval;
u8 *buf;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
addr = ((u16) srb->cmnd[2] << 8) | srb->cmnd[3];
len = ((u16) srb->cmnd[4] << 8) | srb->cmnd[5];
if (addr < 0xe000) {
RTS51X_DEBUGP("filter!addr=0x%x\n", addr);
return TRANSPORT_GOOD;
}
buf = vmalloc(len);
if (!buf)
TRACE_RET(chip, TRANSPORT_ERROR);
for (i = 0; i < len; i++) {
retval = rts51x_ep0_read_register(chip, addr + i, buf + i);
if (retval != STATUS_SUCCESS) {
vfree(buf);
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
rts51x_set_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
vfree(buf);
return TRANSPORT_GOOD;
}
static int write_mem(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
unsigned short addr, len, i;
int retval;
u8 *buf;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
addr = ((u16) srb->cmnd[2] << 8) | srb->cmnd[3];
len = ((u16) srb->cmnd[4] << 8) | srb->cmnd[5];
if (addr < 0xe000) {
RTS51X_DEBUGP("filter!addr=0x%x\n", addr);
return TRANSPORT_GOOD;
}
len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len);
buf = vmalloc(len);
if (!buf)
TRACE_RET(chip, TRANSPORT_ERROR);
rts51x_get_xfer_buf(buf, len, srb);
for (i = 0; i < len; i++) {
retval =
rts51x_ep0_write_register(chip, addr + i, 0xFF, buf[i]);
if (retval != STATUS_SUCCESS) {
vfree(buf);
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
vfree(buf);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
return TRANSPORT_GOOD;
}
static int get_sd_csd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
unsigned int lun = SCSI_LUN(srb);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (get_lun_card(chip, lun) != SD_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
rts51x_set_xfer_buf(sd_card->raw_csd, scsi_bufflen(srb), srb);
return TRANSPORT_GOOD;
}
static int read_phy_register(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int retval;
u8 addr, len, i;
u8 *buf;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
addr = srb->cmnd[5];
len = srb->cmnd[7];
if (len) {
buf = vmalloc(len);
if (!buf)
TRACE_RET(chip, TRANSPORT_ERROR);
for (i = 0; i < len; i++) {
retval =
rts51x_read_phy_register(chip, addr + i, buf + i);
if (retval != STATUS_SUCCESS) {
vfree(buf);
set_sense_type(chip, SCSI_LUN(srb),
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
len = min(scsi_bufflen(srb), (unsigned int)len);
rts51x_set_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
vfree(buf);
}
return TRANSPORT_GOOD;
}
static int write_phy_register(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int retval;
u8 addr, len, i;
u8 *buf;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
addr = srb->cmnd[5];
len = srb->cmnd[7];
if (len) {
len = min(scsi_bufflen(srb), (unsigned int)len);
buf = vmalloc(len);
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
rts51x_get_xfer_buf(buf, len, srb);
scsi_set_resid(srb, scsi_bufflen(srb) - len);
for (i = 0; i < len; i++) {
retval =
rts51x_write_phy_register(chip, addr + i, buf[i]);
if (retval != STATUS_SUCCESS) {
vfree(buf);
set_sense_type(chip, SCSI_LUN(srb),
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
vfree(buf);
}
return TRANSPORT_GOOD;
}
static int get_card_bus_width(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
u8 card, bus_width;
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
card = get_lun_card(chip, lun);
if ((card == SD_CARD) || (card == MS_CARD)) {
bus_width = chip->card_bus_width[lun];
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
rts51x_set_xfer_buf(&bus_width, scsi_bufflen(srb), srb);
return TRANSPORT_GOOD;
}
#ifdef _MSG_TRACE
static int trace_msg_cmd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned char *buf = NULL;
u8 clear;
unsigned int buf_len;
buf_len =
4 +
((2 + MSG_FUNC_LEN + MSG_FILE_LEN + TIME_VAL_LEN) * TRACE_ITEM_CNT);
if ((scsi_bufflen(srb) < buf_len) || (scsi_sglist(srb) == NULL)) {
set_sense_type(chip, SCSI_LUN(srb),
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
clear = srb->cmnd[2];
buf = vmalloc(scsi_bufflen(srb));
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
rts51x_trace_msg(chip, buf, clear);
rts51x_set_xfer_buf(buf, scsi_bufflen(srb), srb);
vfree(buf);
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
#endif
static int rw_mem_cmd_buf(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int retval = STATUS_SUCCESS;
unsigned int lun = SCSI_LUN(srb);
u8 cmd_type, mask, value, idx, mode, len;
u16 addr;
u32 timeout;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
switch (srb->cmnd[3]) {
case INIT_BATCHCMD:
rts51x_init_cmd(chip);
break;
case ADD_BATCHCMD:
cmd_type = srb->cmnd[4];
if (cmd_type > 2) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
addr = (srb->cmnd[5] << 8) | srb->cmnd[6];
mask = srb->cmnd[7];
value = srb->cmnd[8];
rts51x_add_cmd(chip, cmd_type, addr, mask, value);
break;
case SEND_BATCHCMD:
mode = srb->cmnd[4];
len = srb->cmnd[5];
timeout =
((u32) srb->cmnd[6] << 24) | ((u32) srb->
cmnd[7] << 16) | ((u32) srb->
cmnd[8] <<
8) | ((u32)
srb->
cmnd
[9]);
retval = rts51x_send_cmd(chip, mode, 1000);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (mode & STAGE_R) {
retval = rts51x_get_rsp(chip, len, timeout);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
break;
case GET_BATCHRSP:
idx = srb->cmnd[4];
value = chip->rsp_buf[idx];
if (scsi_bufflen(srb) < 1) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
rts51x_set_xfer_buf(&value, 1, srb);
scsi_set_resid(srb, 0);
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, TRANSPORT_FAILED);
}
return TRANSPORT_GOOD;
}
static int suit_cmd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int result;
switch (srb->cmnd[3]) {
case INIT_BATCHCMD:
case ADD_BATCHCMD:
case SEND_BATCHCMD:
case GET_BATCHRSP:
result = rw_mem_cmd_buf(srb, chip);
break;
default:
result = TRANSPORT_ERROR;
}
return result;
}
static int app_cmd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int result;
switch (srb->cmnd[2]) {
case PP_READ10:
case PP_WRITE10:
result = read_write(srb, chip);
break;
case SUIT_CMD:
result = suit_cmd(srb, chip);
break;
case READ_PHY:
result = read_phy_register(srb, chip);
break;
case WRITE_PHY:
result = write_phy_register(srb, chip);
break;
case GET_DEV_STATUS:
result = get_dev_status(srb, chip);
break;
default:
set_sense_type(chip, SCSI_LUN(srb),
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
return result;
}
static int vendor_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int result = TRANSPORT_GOOD;
switch (srb->cmnd[1]) {
case READ_STATUS:
result = read_status(srb, chip);
break;
case READ_MEM:
result = read_mem(srb, chip);
break;
case WRITE_MEM:
result = write_mem(srb, chip);
break;
case GET_BUS_WIDTH:
result = get_card_bus_width(srb, chip);
break;
case GET_SD_CSD:
result = get_sd_csd(srb, chip);
break;
#ifdef _MSG_TRACE
case TRACE_MSG:
result = trace_msg_cmd(srb, chip);
break;
#endif
case SCSI_APP_CMD:
result = app_cmd(srb, chip);
break;
default:
set_sense_type(chip, SCSI_LUN(srb),
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
return result;
}
static int ms_format_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
int retval, quick_format;
if (get_lun_card(chip, lun) != MS_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((srb->cmnd[3] != 0x4D) || (srb->cmnd[4] != 0x47)
|| (srb->cmnd[5] != 0x66) || (srb->cmnd[6] != 0x6D)
|| (srb->cmnd[7] != 0x74)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (srb->cmnd[8] & 0x01)
quick_format = 0;
else
quick_format = 1;
if (!(chip->card_ready & MS_CARD)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (chip->card_wp & MS_CARD) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (!CHK_MSPRO(ms_card)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
retval = mspro_format(srb, chip, MS_SHORT_DATA_LEN, quick_format);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_FORMAT_CMD_FAILED);
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
#ifdef SUPPORT_PCGL_1P18
int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
u8 dev_info_id, data_len;
u8 *buf;
unsigned int buf_len;
int i;
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((get_lun_card(chip, lun) != MS_CARD)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((srb->cmnd[2] != 0xB0) || (srb->cmnd[4] != 0x4D) ||
(srb->cmnd[5] != 0x53) || (srb->cmnd[6] != 0x49) ||
(srb->cmnd[7] != 0x44)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
dev_info_id = srb->cmnd[3];
if ((CHK_MSXC(ms_card) && (dev_info_id == 0x10)) ||
(!CHK_MSXC(ms_card) && (dev_info_id == 0x13)) ||
!CHK_MSPRO(ms_card)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (dev_info_id == 0x15)
buf_len = data_len = 0x3A;
else
buf_len = data_len = 0x6A;
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf)
TRACE_RET(chip, TRANSPORT_ERROR);
i = 0;
/* GET Memory Stick Media Information Response Header */
buf[i++] = 0x00; /* Data length MSB */
buf[i++] = data_len; /* Data length LSB */
/* Device Information Type Code */
if (CHK_MSXC(ms_card))
buf[i++] = 0x03;
else
buf[i++] = 0x02;
/* SGM bit */
buf[i++] = 0x01;
/* Reserved */
buf[i++] = 0x00;
buf[i++] = 0x00;
buf[i++] = 0x00;
/* Number of Device Information */
buf[i++] = 0x01;
/* Device Information Body
* Device Information ID Number */
buf[i++] = dev_info_id;
/* Device Information Length */
if (dev_info_id == 0x15)
data_len = 0x31;
else
data_len = 0x61;
buf[i++] = 0x00; /* Data length MSB */
buf[i++] = data_len; /* Data length LSB */
/* Valid Bit */
buf[i++] = 0x80;
if ((dev_info_id == 0x10) || (dev_info_id == 0x13)) {
/* System Information */
memcpy(buf + i, ms_card->raw_sys_info, 96);
} else {
/* Model Name */
memcpy(buf + i, ms_card->raw_model_name, 48);
}
rts51x_set_xfer_buf(buf, buf_len, srb);
if (dev_info_id == 0x15)
scsi_set_resid(srb, scsi_bufflen(srb) - 0x3C);
else
scsi_set_resid(srb, scsi_bufflen(srb) - 0x6C);
kfree(buf);
return STATUS_SUCCESS;
}
#endif
static int ms_sp_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int retval = TRANSPORT_ERROR;
if (srb->cmnd[2] == MS_FORMAT)
retval = ms_format_cmnd(srb, chip);
#ifdef SUPPORT_PCGL_1P18
else if (srb->cmnd[2] == GET_MS_INFORMATION)
retval = get_ms_information(srb, chip);
#endif
return retval;
}
#ifdef SUPPORT_CPRM
static int sd_extention_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
unsigned int lun = SCSI_LUN(srb);
int result;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
sd_cleanup_work(chip);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((get_lun_card(chip, lun) != SD_CARD)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
switch (srb->cmnd[0]) {
case SD_PASS_THRU_MODE:
result = sd_pass_thru_mode(srb, chip);
break;
case SD_EXECUTE_NO_DATA:
result = sd_execute_no_data(srb, chip);
break;
case SD_EXECUTE_READ:
result = sd_execute_read_data(srb, chip);
break;
case SD_EXECUTE_WRITE:
result = sd_execute_write_data(srb, chip);
break;
case SD_GET_RSP:
result = sd_get_cmd_rsp(srb, chip);
break;
case SD_HW_RST:
result = sd_hw_rst(srb, chip);
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
return result;
}
#endif
#ifdef SUPPORT_MAGIC_GATE
int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
int retval;
u8 key_format;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
ms_cleanup_work(chip);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((get_lun_card(chip, lun) != MS_CARD)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (srb->cmnd[7] != KC_MG_R_PRO) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (!CHK_MSPRO(ms_card)) {
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
TRACE_RET(chip, TRANSPORT_FAILED);
}
key_format = srb->cmnd[10] & 0x3F;
switch (key_format) {
case KF_GET_LOC_EKB:
if ((scsi_bufflen(srb) == 0x41C) &&
(srb->cmnd[8] == 0x04) && (srb->cmnd[9] == 0x1C)) {
retval = mg_get_local_EKB(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
case KF_RSP_CHG:
if ((scsi_bufflen(srb) == 0x24) &&
(srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x24)) {
retval = mg_get_rsp_chg(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
case KF_GET_ICV:
ms_card->mg_entry_num = srb->cmnd[5];
if ((scsi_bufflen(srb) == 0x404) &&
(srb->cmnd[8] == 0x04) &&
(srb->cmnd[9] == 0x04) &&
(srb->cmnd[2] == 0x00) &&
(srb->cmnd[3] == 0x00) &&
(srb->cmnd[4] == 0x00) && (srb->cmnd[5] < 32)) {
retval = mg_get_ICV(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
int retval;
u8 key_format;
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
ms_cleanup_work(chip);
if (!check_card_ready(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (check_card_wp(chip, lun)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_PROTECT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((get_lun_card(chip, lun) != MS_CARD)) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_LUN_NOT_SUPPORT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (srb->cmnd[7] != KC_MG_R_PRO) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (!CHK_MSPRO(ms_card)) {
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
TRACE_RET(chip, TRANSPORT_FAILED);
}
key_format = srb->cmnd[10] & 0x3F;
switch (key_format) {
case KF_SET_LEAF_ID:
if ((scsi_bufflen(srb) == 0x0C) &&
(srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x0C)) {
retval = mg_set_leaf_id(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
case KF_CHG_HOST:
if ((scsi_bufflen(srb) == 0x0C) &&
(srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x0C)) {
retval = mg_chg(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
case KF_RSP_HOST:
if ((scsi_bufflen(srb) == 0x0C) &&
(srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x0C)) {
retval = mg_rsp(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
case KF_SET_ICV:
ms_card->mg_entry_num = srb->cmnd[5];
if ((scsi_bufflen(srb) == 0x404) &&
(srb->cmnd[8] == 0x04) &&
(srb->cmnd[9] == 0x04) &&
(srb->cmnd[2] == 0x00) &&
(srb->cmnd[3] == 0x00) &&
(srb->cmnd[4] == 0x00) && (srb->cmnd[5] < 32)) {
retval = mg_set_ICV(srb, chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
#endif
int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
#ifdef SUPPORT_SD_LOCK
struct sd_info *sd_card = &(chip->sd_card);
#endif
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
int result = TRANSPORT_GOOD;
#ifdef SUPPORT_SD_LOCK
if (sd_card->sd_erase_status) {
/* Block all SCSI command except for REQUEST_SENSE
* and rs_ppstatus */
if (!
((srb->cmnd[0] == VENDOR_CMND)
&& (srb->cmnd[1] == SCSI_APP_CMD)
&& (srb->cmnd[2] == GET_DEV_STATUS))
&& (srb->cmnd[0] != REQUEST_SENSE)) {
/* Logical Unit Not Ready Format in Progress */
set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04,
0, 0);
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
#endif
if ((get_lun_card(chip, lun) == MS_CARD) &&
(ms_card->format_status == FORMAT_IN_PROGRESS)) {
if ((srb->cmnd[0] != REQUEST_SENSE)
&& (srb->cmnd[0] != INQUIRY)) {
/* Logical Unit Not Ready Format in Progress */
set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04,
0, (u16) (ms_card->progress));
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
switch (srb->cmnd[0]) {
case READ_10:
case WRITE_10:
case READ_6:
case WRITE_6:
result = read_write(srb, chip);
break;
case TEST_UNIT_READY:
result = test_unit_ready(srb, chip);
break;
case INQUIRY:
result = inquiry(srb, chip);
break;
case READ_CAPACITY:
result = read_capacity(srb, chip);
break;
case START_STOP:
result = start_stop_unit(srb, chip);
break;
case ALLOW_MEDIUM_REMOVAL:
result = allow_medium_removal(srb, chip);
break;
case REQUEST_SENSE:
result = request_sense(srb, chip);
break;
case MODE_SENSE:
case MODE_SENSE_10:
result = mode_sense(srb, chip);
break;
case 0x23:
result = read_format_capacity(srb, chip);
break;
case VENDOR_CMND:
result = vendor_cmnd(srb, chip);
break;
case MS_SP_CMND:
result = ms_sp_cmnd(srb, chip);
break;
#ifdef SUPPORT_CPRM
case SD_PASS_THRU_MODE:
case SD_EXECUTE_NO_DATA:
case SD_EXECUTE_READ:
case SD_EXECUTE_WRITE:
case SD_GET_RSP:
case SD_HW_RST:
result = sd_extention_cmnd(srb, chip);
break;
#endif
#ifdef SUPPORT_MAGIC_GATE
case CMD_MSPRO_MG_RKEY:
result = mg_report_key(srb, chip);
break;
case CMD_MSPRO_MG_SKEY:
result = mg_send_key(srb, chip);
break;
#endif
case FORMAT_UNIT:
case MODE_SELECT:
case VERIFY:
result = TRANSPORT_GOOD;
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
result = TRANSPORT_FAILED;
}
return result;
}
/***********************************************************************
* Host functions
***********************************************************************/
const char *host_info(struct Scsi_Host *host)
{
return "SCSI emulation for RTS51xx USB driver-based card reader";
}
int slave_alloc(struct scsi_device *sdev)
{
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
* less than 36 bytes.
*/
sdev->inquiry_len = 36;
return 0;
}
int slave_configure(struct scsi_device *sdev)
{
/* Scatter-gather buffers (all but the last) must have a length
* divisible by the bulk maxpacket size. Otherwise a data packet
* would end up being short, causing a premature end to the data
* transfer. Since high-speed bulk pipes have a maxpacket size
* of 512, we'll use that as the scsi device queue's DMA alignment
* mask. Guaranteeing proper alignment of the first buffer will
* have the desired effect because, except at the beginning and
* the end, scatter-gather buffers follow page boundaries. */
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
/* Set the SCSI level to at least 2. We'll leave it at 3 if that's
* what is originally reported. We need this to avoid confusing
* the SCSI layer with devices that report 0 or 1, but need 10-byte
* commands (ala ATAPI devices behind certain bridges, or devices
* which simply have broken INQUIRY data).
*
* NOTE: This means /dev/sg programs (ala cdrecord) will get the
* actual information. This seems to be the preference for
* programs like that.
*
* NOTE: This also means that /proc/scsi/scsi and sysfs may report
* the actual value or the modified one, depending on where the
* data comes from.
*/
if (sdev->scsi_level < SCSI_2)
sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
return 0;
}
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/
/* we use this macro to help us write into the buffer */
#undef SPRINTF
#define SPRINTF(args...) \
do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
int proc_info(struct Scsi_Host *host, char *buffer,
char **start, off_t offset, int length, int inout)
{
char *pos = buffer;
/* if someone is sending us data, just throw it away */
if (inout)
return length;
/* print the controller name */
SPRINTF(" Host scsi%d: %s\n", host->host_no, RTS51X_NAME);
/* print product, vendor, and driver version strings */
SPRINTF(" Vendor: Realtek Corp.\n");
SPRINTF(" Product: RTS51xx USB Card Reader\n");
SPRINTF(" Version: %s\n", DRIVER_VERSION);
SPRINTF(" Build: %s\n", __TIME__);
/*
* Calculate start of next buffer, and return value.
*/
*start = buffer + offset;
if ((pos - buffer) < offset)
return 0;
else if ((pos - buffer - offset) < length)
return pos - buffer - offset;
else
return length;
}
/* queue a command */
/* This is always called with scsi_lock(host) held */
int queuecommand_lck(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
{
struct rts51x_chip *chip = host_to_rts51x(srb->device->host);
/* check for state-transition errors */
if (chip->srb != NULL) {
RTS51X_DEBUGP("Error in %s: chip->srb = %p\n",
__func__, chip->srb);
return SCSI_MLQUEUE_HOST_BUSY;
}
/* fail the command if we are disconnecting */
if (test_bit(FLIDX_DISCONNECTING, &chip->usb->dflags)) {
RTS51X_DEBUGP("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;
chip->srb = srb;
complete(&chip->usb->cmnd_ready);
return 0;
}
#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
{
return queuecommand_lck(srb, done);
}
#else
DEF_SCSI_QCMD(queuecommand)
#endif
/***********************************************************************
* Error handling functions
***********************************************************************/
/* Command timeout and abort */
int command_abort(struct scsi_cmnd *srb)
{
struct rts51x_chip *chip = host_to_rts51x(srb->device->host);
RTS51X_DEBUGP("%s called\n", __func__);
/* us->srb together with the TIMED_OUT, RESETTING, and ABORTING
* bits are protected by the host lock. */
scsi_lock(rts51x_to_host(chip));
/* Is this command still active? */
if (chip->srb != srb) {
scsi_unlock(rts51x_to_host(chip));
RTS51X_DEBUGP("-- nothing to abort\n");
return FAILED;
}
/* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if
* a device reset isn't already in progress (to avoid interfering
* with the reset). Note that we must retain the host lock while
* calling usb_stor_stop_transport(); otherwise it might interfere
* with an auto-reset that begins as soon as we release the lock. */
set_bit(FLIDX_TIMED_OUT, &chip->usb->dflags);
if (!test_bit(FLIDX_RESETTING, &chip->usb->dflags)) {
set_bit(FLIDX_ABORTING, &chip->usb->dflags);
/* rts51x_stop_transport(us); */
}
scsi_unlock(rts51x_to_host(chip));
/* Wait for the aborted command to finish */
wait_for_completion(&chip->usb->notify);
return SUCCESS;
}
/* This invokes the transport reset mechanism to reset the state of the
* device */
int device_reset(struct scsi_cmnd *srb)
{
int result = 0;
RTS51X_DEBUGP("%s called\n", __func__);
return result < 0 ? FAILED : SUCCESS;
}
/* Simulate a SCSI bus reset by resetting the device's USB port. */
int bus_reset(struct scsi_cmnd *srb)
{
int result = 0;
RTS51X_DEBUGP("%s called\n", __func__);
return result < 0 ? FAILED : SUCCESS;
}
static const char *rts5139_info(struct Scsi_Host *host)
{
return "SCSI emulation for RTS5139 USB card reader";
}
struct scsi_host_template rts51x_host_template = {
/* basic userland interface stuff */
.name = RTS51X_NAME,
.proc_name = RTS51X_NAME,
.proc_info = proc_info,
.info = rts5139_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
};
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_SCSI_H
#define __RTS51X_SCSI_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 "rts51x_chip.h"
#define MS_SP_CMND 0xFA
#define MS_FORMAT 0xA0
#define GET_MS_INFORMATION 0xB0
#define VENDOR_CMND 0xF0
#define READ_STATUS 0x09
#define READ_MEM 0x0D
#define WRITE_MEM 0x0E
#define GET_BUS_WIDTH 0x13
#define GET_SD_CSD 0x14
#define TOGGLE_GPIO 0x15
#define TRACE_MSG 0x18
#define SCSI_APP_CMD 0x10
#define PP_READ10 0x1A
#define PP_WRITE10 0x0A
#define READ_HOST_REG 0x1D
#define WRITE_HOST_REG 0x0D
#define SET_VAR 0x05
#define GET_VAR 0x15
#define DMA_READ 0x16
#define DMA_WRITE 0x06
#define GET_DEV_STATUS 0x10
#define SET_CHIP_MODE 0x27
#define SUIT_CMD 0xE0
#define WRITE_PHY 0x07
#define READ_PHY 0x17
#define INIT_BATCHCMD 0x41
#define ADD_BATCHCMD 0x42
#define SEND_BATCHCMD 0x43
#define GET_BATCHRSP 0x44
#ifdef SUPPORT_CPRM
/* SD Pass Through Command Extention */
#define SD_PASS_THRU_MODE 0xD0
#define SD_EXECUTE_NO_DATA 0xD1
#define SD_EXECUTE_READ 0xD2
#define SD_EXECUTE_WRITE 0xD3
#define SD_GET_RSP 0xD4
#define SD_HW_RST 0xD6
#endif
#ifdef SUPPORT_MAGIC_GATE
#define CMD_MSPRO_MG_RKEY 0xA4 /* Report Key Command */
#define CMD_MSPRO_MG_SKEY 0xA3 /* Send Key Command */
/* CBWCB field: key class */
#define KC_MG_R_PRO 0xBE /* MG-R PRO */
/* CBWCB field: key format */
#define KF_SET_LEAF_ID 0x31 /* Set Leaf ID */
#define KF_GET_LOC_EKB 0x32 /* Get Local EKB */
#define KF_CHG_HOST 0x33 /* Challenge (host) */
#define KF_RSP_CHG 0x34 /* Response and Challenge (device) */
#define KF_RSP_HOST 0x35 /* Response (host) */
#define KF_GET_ICV 0x36 /* Get ICV */
#define KF_SET_ICV 0x37 /* SSet ICV */
#endif
struct rts51x_chip;
/*-----------------------------------
Start-Stop-Unit
-----------------------------------*/
#define STOP_MEDIUM 0x00 /* access disable */
#define MAKE_MEDIUM_READY 0x01 /* access enable */
#define UNLOAD_MEDIUM 0x02 /* unload */
#define LOAD_MEDIUM 0x03 /* load */
/*-----------------------------------
STANDARD_INQUIRY
-----------------------------------*/
#define QULIFIRE 0x00
#define AENC_FNC 0x00
#define TRML_IOP 0x00
#define REL_ADR 0x00
#define WBUS_32 0x00
#define WBUS_16 0x00
#define SYNC 0x00
#define LINKED 0x00
#define CMD_QUE 0x00
#define SFT_RE 0x00
#define VEN_ID_LEN 8 /* Vendor ID Length */
#define PRDCT_ID_LEN 16 /* Product ID Length */
#define PRDCT_REV_LEN 4 /* Product LOT Length */
#define DRCT_ACCESS_DEV 0x00 /* Direct Access Device */
#define RMB_DISC 0x80 /* The Device is Removable */
#define ANSI_SCSI2 0x02 /* Based on ANSI-SCSI2 */
#define SCSI 0x00 /* Interface ID */
void scsi_show_command(struct scsi_cmnd *srb);
void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type);
void set_sense_data(struct rts51x_chip *chip, unsigned int lun, u8 err_code,
u8 sense_key, u32 info, u8 asc, u8 ascq, u8 sns_key_info0,
u16 sns_key_info1);
int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip);
struct Scsi_Host;
struct scsi_device;
struct scsi_cmnd;
const char *host_info(struct Scsi_Host *host);
int slave_alloc(struct scsi_device *sdev);
int slave_configure(struct scsi_device *sdev);
int proc_info(struct Scsi_Host *host, char *buffer,
char **start, off_t offset, int length, int inout);
#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *));
#else
int queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
#endif
int command_abort(struct scsi_cmnd *srb);
int device_reset(struct scsi_cmnd *srb);
int bus_reset(struct scsi_cmnd *srb);
#endif /* __RTS51X_SCSI_H */
/* Driver for Realtek USB RTS51xx card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_SYS_H
#define __RTS51X_SYS_H
#include "rts51x.h"
#include "rts51x_chip.h"
#include "rts51x_card.h"
#define USING_POLLING_CYCLE_DELINK
extern int rts51x_check_start_time(struct rts51x_chip *chip);
extern void rts51x_set_start_time(struct rts51x_chip *chip);
extern void rts51x_clear_start_time(struct rts51x_chip *chip);
/* typedef dma_addr_t ULONG_PTR; */
static inline void rts51x_reset_detected_cards(struct rts51x_chip *chip)
{
/* rts51x_reset_cards(chip); */
}
static inline void clear_first_install_mark(struct rts51x_chip *chip)
{
}
void rts51x_enter_ss(struct rts51x_chip *chip);
void rts51x_exit_ss(struct rts51x_chip *chip);
#endif /* __RTS51X_SYS_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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 <scsi/scsi.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include "debug.h"
#include "rts51x.h"
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_scsi.h"
#include "rts51x_transport.h"
#include "trace.h"
/***********************************************************************
* Scatter-gather transfer buffer access routines
***********************************************************************/
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
* Update the **sgptr and *offset variables so that the next copy will
* pick up from where this one left off.
*/
unsigned int rts51x_access_sglist(unsigned char *buffer,
unsigned int buflen, void *sglist,
void **sgptr, unsigned int *offset,
enum xfer_buf_dir dir)
{
unsigned int cnt;
struct scatterlist *sg = (struct scatterlist *)*sgptr;
/* We have to go through the list one entry
* at a time. Each s-g entry contains some number of pages, and
* each page has to be kmap()'ed separately. If the page is already
* in kernel-addressable memory then kmap() will return its address.
* If the page is not directly accessible -- such as a user buffer
* located in high memory -- then kmap() will map it to a temporary
* position in the kernel's virtual address space.
*/
if (!sg)
sg = (struct scatterlist *)sglist;
/* This loop handles a single s-g list entry, which may
* include multiple pages. Find the initial page structure
* and the starting offset within the page, and update
* the *offset and **sgptr values for the next loop.
*/
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);
}
/* Transfer the data for all the pages in this
* s-g entry. For each page: call kmap(), do the
* transfer, and call kunmap() immediately after. */
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;
}
unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb,
struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
{
return rts51x_access_sglist(buffer, buflen, (void *)scsi_sglist(srb),
(void **)sgptr, offset, dir);
}
/* Store the contents of buffer into srb's transfer buffer and set the
* SCSI residue.
*/
void rts51x_set_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int offset = 0;
struct scatterlist *sg = NULL;
buflen = min(buflen, scsi_bufflen(srb));
buflen = rts51x_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
TO_XFER_BUF);
if (buflen < scsi_bufflen(srb))
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
void rts51x_get_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int offset = 0;
struct scatterlist *sg = NULL;
buflen = min(buflen, scsi_bufflen(srb));
buflen = rts51x_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
FROM_XFER_BUF);
if (buflen < scsi_bufflen(srb))
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
}
/* This is the completion handler which will wake us up when an URB
* completes.
*/
static void urb_done_completion(struct urb *urb)
{
struct completion *urb_done_ptr = urb->context;
if (urb_done_ptr)
complete(urb_done_ptr);
}
/* This is the common part of the URB message submission code
*
* All URBs from the driver involved in handling a queued scsi
* command _must_ pass through this function (or something like it) for the
* abort mechanisms to work properly.
*/
static int rts51x_msg_common(struct rts51x_chip *chip, struct urb *urb,
int timeout)
{
struct rts51x_usb *rts51x = chip->usb;
struct completion urb_done;
long timeleft;
int status;
/* don't submit URBs during abort processing */
if (test_bit(FLIDX_ABORTING, &rts51x->dflags))
TRACE_RET(chip, -EIO);
/* set up data structures for the wakeup system */
init_completion(&urb_done);
/* fill the common fields in the URB */
urb->context = &urb_done;
urb->actual_length = 0;
urb->error_count = 0;
urb->status = 0;
/* we assume that if transfer_buffer isn't us->iobuf then it
* hasn't been mapped for DMA. Yes, this is clunky, but it's
* easier than always having the caller tell us whether the
* transfer buffer has already been mapped. */
urb->transfer_flags = URB_NO_SETUP_DMA_MAP;
if (urb->transfer_buffer == rts51x->iobuf) {
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = rts51x->iobuf_dma;
}
urb->setup_dma = rts51x->cr_dma;
/* submit the URB */
status = usb_submit_urb(urb, GFP_NOIO);
if (status) {
/* something went wrong */
TRACE_RET(chip, status);
}
/* since the URB has been submitted successfully, it's now okay
* to cancel it */
set_bit(FLIDX_URB_ACTIVE, &rts51x->dflags);
/* did an abort occur during the submission? */
if (test_bit(FLIDX_ABORTING, &rts51x->dflags)) {
/* cancel the URB, if it hasn't been cancelled already */
if (test_and_clear_bit(FLIDX_URB_ACTIVE, &rts51x->dflags)) {
RTS51X_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(urb);
}
}
/* wait for the completion of the URB */
timeleft =
wait_for_completion_interruptible_timeout(&urb_done,
(timeout * HZ /
1000) ? :
MAX_SCHEDULE_TIMEOUT);
clear_bit(FLIDX_URB_ACTIVE, &rts51x->dflags);
if (timeleft <= 0) {
RTS51X_DEBUGP("%s -- cancelling URB\n",
timeleft == 0 ? "Timeout" : "Signal");
usb_kill_urb(urb);
if (timeleft == 0)
status = -ETIMEDOUT;
else
status = -EINTR;
} else {
status = urb->status;
}
return status;
}
/*
* Interpret the results of a URB transfer
*/
static int interpret_urb_result(struct rts51x_chip *chip, unsigned int pipe,
unsigned int length, int result,
unsigned int partial)
{
int retval = STATUS_SUCCESS;
/* RTS51X_DEBUGP("Status code %d; transferred %u/%u\n",
result, partial, length); */
switch (result) {
/* no error code; did we send all the data? */
case 0:
if (partial != length) {
RTS51X_DEBUGP("-- short transfer\n");
TRACE_RET(chip, STATUS_TRANS_SHORT);
}
/* RTS51X_DEBUGP("-- transfer complete\n"); */
return STATUS_SUCCESS;
/* stalled */
case -EPIPE:
/* for control endpoints, (used by CB[I]) a stall indicates
* a failed command */
if (usb_pipecontrol(pipe)) {
RTS51X_DEBUGP("-- stall on control pipe\n");
TRACE_RET(chip, STATUS_STALLED);
}
/* for other sorts of endpoint, clear the stall */
RTS51X_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
if (rts51x_clear_halt(chip, pipe) < 0)
TRACE_RET(chip, STATUS_ERROR);
retval = STATUS_STALLED;
TRACE_GOTO(chip, Exit);
/* babble - the device tried to send more than
* we wanted to read */
case -EOVERFLOW:
RTS51X_DEBUGP("-- babble\n");
retval = STATUS_TRANS_LONG;
TRACE_GOTO(chip, Exit);
/* the transfer was cancelled by abort,
* disconnect, or timeout */
case -ECONNRESET:
RTS51X_DEBUGP("-- transfer cancelled\n");
retval = STATUS_ERROR;
TRACE_GOTO(chip, Exit);
/* short scatter-gather read transfer */
case -EREMOTEIO:
RTS51X_DEBUGP("-- short read transfer\n");
retval = STATUS_TRANS_SHORT;
TRACE_GOTO(chip, Exit);
/* abort or disconnect in progress */
case -EIO:
RTS51X_DEBUGP("-- abort or disconnect in progress\n");
retval = STATUS_ERROR;
TRACE_GOTO(chip, Exit);
case -ETIMEDOUT:
RTS51X_DEBUGP("-- time out\n");
retval = STATUS_TIMEDOUT;
TRACE_GOTO(chip, Exit);
/* the catch-all error case */
default:
RTS51X_DEBUGP("-- unknown error\n");
retval = STATUS_ERROR;
TRACE_GOTO(chip, Exit);
}
Exit:
if ((retval != STATUS_SUCCESS) && !usb_pipecontrol(pipe))
rts51x_clear_hw_error(chip);
return retval;
}
int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size, int timeout)
{
struct rts51x_usb *rts51x = chip->usb;
int result;
RTS51X_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
__func__, request, requesttype, value, index, size);
/* fill in the devrequest structure */
rts51x->cr->bRequestType = requesttype;
rts51x->cr->bRequest = request;
rts51x->cr->wValue = cpu_to_le16(value);
rts51x->cr->wIndex = cpu_to_le16(index);
rts51x->cr->wLength = cpu_to_le16(size);
/* fill and submit the URB */
usb_fill_control_urb(rts51x->current_urb, rts51x->pusb_dev, pipe,
(unsigned char *)rts51x->cr, data, size,
urb_done_completion, NULL);
result = rts51x_msg_common(chip, rts51x->current_urb, timeout);
return interpret_urb_result(chip, pipe, size, result,
rts51x->current_urb->actual_length);
}
int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe);
if (usb_pipein(pipe))
endp |= USB_DIR_IN;
result = rts51x_ctrl_transfer(chip, SND_CTRL_PIPE(chip),
USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, endp, NULL, 0, 3000);
if (result != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
usb_reset_endpoint(chip->usb->pusb_dev, endp);
return STATUS_SUCCESS;
}
int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe)
{
return rts51x_clear_halt(chip, pipe);
}
static void rts51x_sg_clean(struct usb_sg_request *io)
{
if (io->urbs) {
while (io->entries--)
usb_free_urb(io->urbs[io->entries]);
kfree(io->urbs);
io->urbs = NULL;
}
#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) */
if (io->dev->dev.dma_mask != NULL)
usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
io->sg, io->nents);
#endif
io->dev = NULL;
}
#if 0
static void rts51x_sg_complete(struct urb *urb)
{
struct usb_sg_request *io = urb->context;
int status = urb->status;
spin_lock(&io->lock);
/* In 2.5 we require hcds' endpoint queues not to progress after fault
* reports, until the completion callback (this!) returns. That lets
* device driver code (like this routine) unlink queued urbs first,
* if it needs to, since the HC won't work on them at all. So it's
* not possible for page N+1 to overwrite page N, and so on.
*
* That's only for "hard" faults; "soft" faults (unlinks) sometimes
* complete before the HCD can get requests away from hardware,
* though never during cleanup after a hard fault.
*/
if (io->status
&& (io->status != -ECONNRESET
|| status != -ECONNRESET)
&& urb->actual_length) {
dev_err(io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
status, io->status);
/* BUG (); */
}
if (io->status == 0 && status && status != -ECONNRESET) {
int i, found, retval;
io->status = status;
/* the previous urbs, and this one, completed already.
* unlink pending urbs so they won't rx/tx bad data.
* careful: unlink can sometimes be synchronous...
*/
spin_unlock(&io->lock);
for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs[i] || !io->urbs[i]->dev)
continue;
if (found) {
retval = usb_unlink_urb(io->urbs[i]);
if (retval != -EINPROGRESS &&
retval != -ENODEV &&
retval != -EBUSY)
dev_err(&io->dev->dev,
"%s, unlink --> %d\n",
__func__, retval);
} else if (urb == io->urbs[i])
found = 1;
}
spin_lock(&io->lock);
}
urb->dev = NULL;
/* on the last completion, signal usb_sg_wait() */
io->bytes += urb->actual_length;
io->count--;
if (!io->count)
complete(&io->complete);
spin_unlock(&io->lock);
}
/* This function is ported from usb_sg_init, which can transfer
* sg list partially */
int rts51x_sg_init_partial(struct usb_sg_request *io, struct usb_device *dev,
unsigned pipe, unsigned period, void *buf, struct scatterlist **sgptr,
unsigned int *offset, int nents, size_t length, gfp_t mem_flags)
{
int i;
int urb_flags;
int dma;
struct scatterlist *sg = *sgptr, *first_sg;
first_sg = (struct scatterlist *)buf;
if (!sg)
sg = first_sg;
if (!io || !dev || !sg
|| usb_pipecontrol(pipe)
|| usb_pipeisoc(pipe)
|| (nents <= 0))
return -EINVAL;
spin_lock_init(&io->lock);
io->dev = dev;
io->pipe = pipe;
io->sg = first_sg; /* used by unmap */
io->nents = nents;
RTS51X_DEBUGP("Before map, sg address: 0x%x\n", (unsigned int)sg);
RTS51X_DEBUGP("Before map, dev address: 0x%x\n", (unsigned int)dev);
/* not all host controllers use DMA (like the mainstream pci ones);
* they can use PIO (sl811) or be software over another transport.
*/
dma = (dev->dev.dma_mask != NULL);
if (dma) {
/* map the whole sg list, because here we only know the
* total nents */
io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
first_sg, nents);
} else {
io->entries = nents;
}
/* initialize all the urbs we'll use */
if (io->entries <= 0)
return io->entries;
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
if (!io->urbs)
goto nomem;
urb_flags = URB_NO_INTERRUPT;
if (dma)
urb_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
RTS51X_DEBUGP("io->entries = %d\n", io->entries);
for (i = 0; (sg != NULL) && (length > 0); i++) {
unsigned len;
RTS51X_DEBUGP("sg address: 0x%x\n", (unsigned int)sg);
RTS51X_DEBUGP("length = %d, *offset = %d\n", length, *offset);
io->urbs[i] = usb_alloc_urb(0, mem_flags);
if (!io->urbs[i]) {
io->entries = i;
goto nomem;
}
io->urbs[i]->dev = NULL;
io->urbs[i]->pipe = pipe;
io->urbs[i]->interval = period;
io->urbs[i]->transfer_flags = urb_flags;
io->urbs[i]->complete = rts51x_sg_complete;
io->urbs[i]->context = io;
if (dma) {
io->urbs[i]->transfer_dma =
sg_dma_address(sg) + *offset;
len = sg_dma_len(sg) - *offset;
io->urbs[i]->transfer_buffer = NULL;
RTS51X_DEBUGP(" -- sg entry dma length = %d\n",
sg_dma_len(sg));
} else {
/* hc may use _only_ transfer_buffer */
io->urbs[i]->transfer_buffer = sg_virt(sg) + *offset;
len = sg->length - *offset;
RTS51X_DEBUGP(" -- sg entry length = %d\n",
sg->length);
}
if (length >= len) {
*offset = 0;
io->urbs[i]->transfer_buffer_length = len;
length -= len;
sg = sg_next(sg);
} else {
*offset += length;
io->urbs[i]->transfer_buffer_length = length;
length = 0;
}
if (length == 0)
io->entries = i + 1;
#if 0
if (length) {
len = min_t(unsigned, len, length);
length -= len;
if (length == 0) {
io->entries = i + 1;
*offset += len;
} else {
*offset = 0;
}
}
#endif
}
RTS51X_DEBUGP("In %s, urb count: %d\n", __func__, i);
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
RTS51X_DEBUGP("sg address stored in sgptr: 0x%x\n", (unsigned int)sg);
*sgptr = sg;
/* transaction state */
io->count = io->entries;
io->status = 0;
io->bytes = 0;
init_completion(&io->complete);
return 0;
nomem:
rts51x_sg_clean(io);
return -ENOMEM;
}
#endif
int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
unsigned pipe, unsigned period, struct scatterlist *sg,
int nents, size_t length, gfp_t mem_flags)
{
return usb_sg_init(io, dev, pipe, period, sg, nents, length, mem_flags);
}
int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
{
long timeleft;
int i;
int entries = io->entries;
/* queue the urbs. */
spin_lock_irq(&io->lock);
i = 0;
while (i < entries && !io->status) {
int retval;
io->urbs[i]->dev = io->dev;
retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC);
/* after we submit, let completions or cancelations fire;
* we handshake using io->status.
*/
spin_unlock_irq(&io->lock);
switch (retval) {
/* maybe we retrying will recover */
case -ENXIO: /* hc didn't queue this one */
case -EAGAIN:
case -ENOMEM:
io->urbs[i]->dev = NULL;
retval = 0;
yield();
break;
/* no error? continue immediately.
*
* NOTE: to work better with UHCI (4K I/O buffer may
* need 3K of TDs) it may be good to limit how many
* URBs are queued at once; N milliseconds?
*/
case 0:
++i;
cpu_relax();
break;
/* fail any uncompleted urbs */
default:
io->urbs[i]->dev = NULL;
io->urbs[i]->status = retval;
dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
__func__, retval);
usb_sg_cancel(io);
}
spin_lock_irq(&io->lock);
if (retval && (io->status == 0 || io->status == -ECONNRESET))
io->status = retval;
}
io->count -= entries - i;
if (io->count == 0)
complete(&io->complete);
spin_unlock_irq(&io->lock);
timeleft =
wait_for_completion_interruptible_timeout(&io->complete,
(timeout * HZ /
1000) ? :
MAX_SCHEDULE_TIMEOUT);
if (timeleft <= 0) {
RTS51X_DEBUGP("%s -- cancelling SG request\n",
timeleft == 0 ? "Timeout" : "Signal");
usb_sg_cancel(io);
if (timeleft == 0)
io->status = -ETIMEDOUT;
else
io->status = -EINTR;
}
rts51x_sg_clean(io);
return io->status;
}
/*
* Transfer a scatter-gather list via bulk transfer
*
* This function does basically the same thing as usb_stor_bulk_transfer_buf()
* above, but it uses the usbcore scatter-gather library.
*/
static int rts51x_bulk_transfer_sglist(struct rts51x_chip *chip,
unsigned int pipe,
struct scatterlist *sg, int num_sg,
unsigned int length,
unsigned int *act_len, int timeout)
{
int result;
/* don't submit s-g requests during abort processing */
if (test_bit(FLIDX_ABORTING, &chip->usb->dflags))
TRACE_RET(chip, STATUS_ERROR);
/* initialize the scatter-gather request block */
RTS51X_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
length, num_sg);
result =
rts51x_sg_init(&chip->usb->current_sg, chip->usb->pusb_dev, pipe, 0,
sg, num_sg, length, GFP_NOIO);
if (result) {
RTS51X_DEBUGP("rts51x_sg_init returned %d\n", result);
TRACE_RET(chip, STATUS_ERROR);
}
/* since the block has been initialized successfully, it's now
* okay to cancel it */
set_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
/* did an abort occur during the submission? */
if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) {
/* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags)) {
RTS51X_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(&chip->usb->current_sg);
}
}
/* wait for the completion of the transfer */
result = rts51x_sg_wait(&chip->usb->current_sg, timeout);
clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
/* result = us->current_sg.status; */
if (act_len)
*act_len = chip->usb->current_sg.bytes;
return interpret_urb_result(chip, pipe, length, result,
chip->usb->current_sg.bytes);
}
#if 0
static int rts51x_bulk_transfer_sglist_partial(struct rts51x_chip *chip,
unsigned int pipe, void *buf, struct scatterlist **sgptr,
unsigned int *offset, int num_sg, unsigned int length,
unsigned int *act_len, int timeout)
{
int result;
/* don't submit s-g requests during abort processing */
if (test_bit(FLIDX_ABORTING, &chip->usb->dflags))
TRACE_RET(chip, STATUS_ERROR);
/* initialize the scatter-gather request block */
RTS51X_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
length, num_sg);
result = rts51x_sg_init_partial(&chip->usb->current_sg,
chip->usb->pusb_dev, pipe, 0, buf, sgptr, offset,
num_sg, length, GFP_NOIO);
if (result) {
RTS51X_DEBUGP("rts51x_sg_init_partial returned %d\n", result);
TRACE_RET(chip, STATUS_ERROR);
}
/* since the block has been initialized successfully, it's now
* okay to cancel it */
set_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
/* did an abort occur during the submission? */
if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) {
/* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags)) {
RTS51X_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(&chip->usb->current_sg);
}
}
/* wait for the completion of the transfer */
result = rts51x_sg_wait(&chip->usb->current_sg, timeout);
clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
/* result = us->current_sg.status; */
if (act_len)
*act_len = chip->usb->current_sg.bytes;
return interpret_urb_result(chip, pipe, length, result,
chip->usb->current_sg.bytes);
}
#endif
int rts51x_bulk_transfer_buf(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int length,
unsigned int *act_len, int timeout)
{
int result;
/* fill and submit the URB */
usb_fill_bulk_urb(chip->usb->current_urb, chip->usb->pusb_dev, pipe,
buf, length, urb_done_completion, NULL);
result = rts51x_msg_common(chip, chip->usb->current_urb, timeout);
/* store the actual length of the data transferred */
if (act_len)
*act_len = chip->usb->current_urb->actual_length;
return interpret_urb_result(chip, pipe, length, result,
chip->usb->current_urb->actual_length);
}
int rts51x_transfer_data(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int len, int use_sg,
unsigned int *act_len, int timeout)
{
int result;
if (timeout < 600)
timeout = 600;
if (use_sg) {
result =
rts51x_bulk_transfer_sglist(chip, pipe,
(struct scatterlist *)buf,
use_sg, len, act_len, timeout);
} else {
result =
rts51x_bulk_transfer_buf(chip, pipe, buf, len, act_len,
timeout);
}
return result;
}
int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe,
void *buf, void **ptr, unsigned int *offset,
unsigned int len, int use_sg,
unsigned int *act_len, int timeout)
{
int result;
if (timeout < 600)
timeout = 600;
if (use_sg) {
void *tmp_buf = kmalloc(len, GFP_KERNEL);
if (!tmp_buf)
TRACE_RET(chip, STATUS_NOMEM);
if (usb_pipeout(pipe)) {
rts51x_access_sglist(tmp_buf, len, buf, ptr, offset,
FROM_XFER_BUF);
}
result =
rts51x_bulk_transfer_buf(chip, pipe, tmp_buf, len, act_len,
timeout);
if (result == STATUS_SUCCESS) {
if (usb_pipein(pipe)) {
rts51x_access_sglist(tmp_buf, len, buf, ptr,
offset, TO_XFER_BUF);
}
}
kfree(tmp_buf);
#if 0
result = rts51x_bulk_transfer_sglist_partial(chip, pipe, buf,
(struct scatterlist **)ptr, offset,
use_sg, len, act_len, timeout);
#endif
} else {
unsigned int step = 0;
if (offset)
step = *offset;
result =
rts51x_bulk_transfer_buf(chip, pipe, buf + step, len,
act_len, timeout);
if (act_len)
step += *act_len;
else
step += len;
if (offset)
*offset = step;
}
return result;
}
int rts51x_get_epc_status(struct rts51x_chip *chip, u16 * status)
{
unsigned int pipe = RCV_INTR_PIPE(chip);
struct usb_host_endpoint *ep;
struct completion urb_done;
int result;
if (!status)
TRACE_RET(chip, STATUS_ERROR);
/* set up data structures for the wakeup system */
init_completion(&urb_done);
ep = chip->usb->pusb_dev->ep_in[usb_pipeendpoint(pipe)];
/* fill and submit the URB */
/* We set interval to 1 here, so the polling interval is controlled
* by our polling thread */
usb_fill_int_urb(chip->usb->intr_urb, chip->usb->pusb_dev, pipe,
status, 2, urb_done_completion, &urb_done, 1);
result = rts51x_msg_common(chip, chip->usb->intr_urb, 50);
return interpret_urb_result(chip, pipe, 2, result,
chip->usb->intr_urb->actual_length);
}
u8 media_not_present[] = {
0x70, 0, 0x02, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0x3A, 0, 0, 0, 0, 0 };
u8 invalid_cmd_field[] = {
0x70, 0, 0x05, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0 };
void rts51x_invoke_transport(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
int result;
#ifdef CONFIG_PM
if (chip->option.ss_en) {
if (srb->cmnd[0] == TEST_UNIT_READY) {
if (RTS51X_CHK_STAT(chip, STAT_SS)) {
if (check_fake_card_ready(chip,
SCSI_LUN(srb))) {
srb->result = SAM_STAT_GOOD;
} else {
srb->result = SAM_STAT_CHECK_CONDITION;
memcpy(srb->sense_buffer,
media_not_present, SENSE_SIZE);
}
return;
}
} else if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
if (RTS51X_CHK_STAT(chip, STAT_SS)) {
int prevent = srb->cmnd[4] & 0x1;
if (prevent) {
srb->result = SAM_STAT_CHECK_CONDITION;
memcpy(srb->sense_buffer,
invalid_cmd_field, SENSE_SIZE);
} else {
srb->result = SAM_STAT_GOOD;
}
return;
}
} else {
if (RTS51X_CHK_STAT(chip, STAT_SS)
|| RTS51X_CHK_STAT(chip, STAT_SS_PRE)) {
/* Wake up device */
RTS51X_DEBUGP("Try to wake up device\n");
chip->resume_from_scsi = 1;
rts51x_try_to_exit_ss(chip);
if (RTS51X_CHK_STAT(chip, STAT_SS)) {
wait_timeout(3000);
rts51x_init_chip(chip);
rts51x_init_cards(chip);
}
}
}
}
#endif
result = rts51x_scsi_handler(srb, chip);
/* if there is a transport error, reset and don't auto-sense */
if (result == TRANSPORT_ERROR) {
RTS51X_DEBUGP("-- transport indicates error, resetting\n");
srb->result = DID_ERROR << 16;
goto Handle_Errors;
}
srb->result = SAM_STAT_GOOD;
/*
* If we have a failure, we're going to do a REQUEST_SENSE
* automatically. Note that we differentiate between a command
* "failure" and an "error" in the transport mechanism.
*/
if (result == TRANSPORT_FAILED) {
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
memcpy(srb->sense_buffer,
(unsigned char *)&(chip->sense_buffer[SCSI_LUN(srb)]),
sizeof(struct sense_data_t));
}
return;
/* Error and abort processing: try to resynchronize with the device
* by issuing a port reset. If that fails, try a class-specific
* device reset. */
Handle_Errors:
return;
}
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_TRANSPORT_H
#define __RTS51X_TRANSPORT_H
#include <linux/kernel.h>
#include <linux/version.h>
#include "rts51x.h"
#include "rts51x_chip.h"
#if 1 /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34) */
#define URB_NO_SETUP_DMA_MAP 0
#endif
unsigned int rts51x_access_sglist(unsigned char *buffer,
unsigned int buflen, void *sglist,
void **sgptr, unsigned int *offset,
enum xfer_buf_dir dir);
unsigned int rts51x_access_xfer_buf(unsigned char *buffer, unsigned int buflen,
struct scsi_cmnd *srb,
struct scatterlist **sgptr,
unsigned int *offset,
enum xfer_buf_dir dir);
void rts51x_set_xfer_buf(unsigned char *buffer, unsigned int buflen,
struct scsi_cmnd *srb);
void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
struct scsi_cmnd *srb);
int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size, int timeout);
int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
int rts51x_transfer_data(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int len, int use_sg,
unsigned int *act_len, int timeout);
int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe,
void *buf, void **ptr, unsigned int *offset,
unsigned int len, int use_sg,
unsigned int *act_len, int timeout);
/* whichPipe:
* 0: bulk in pipe
* 1: bulk out pipe
* 2: intr in pipe */
int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe);
#ifndef POLLING_IN_THREAD
int rts51x_start_epc_transfer(struct rts51x_chip *chip);
void rts51x_cancel_epc_transfer(struct rts51x_chip *chip);
#endif
int rts51x_get_epc_status(struct rts51x_chip *chip, u16 * status);
void rts51x_invoke_transport(struct scsi_cmnd *srb, struct rts51x_chip *chip);
#endif /* __RTS51X_TRANSPORT_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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 "debug.h"
#include "trace.h"
#include "rts51x.h"
#include "rts51x_transport.h"
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "sd.h"
static inline void sd_set_reset_fail(struct rts51x_chip *chip, u8 err_code)
{
struct sd_info *sd_card = &(chip->sd_card);
sd_card->sd_reset_fail |= err_code;
}
static inline void sd_clear_reset_fail(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
sd_card->sd_reset_fail = 0;
}
static inline int sd_check_reset_fail(struct rts51x_chip *chip, u8 err_code)
{
struct sd_info *sd_card = &(chip->sd_card);
return sd_card->sd_reset_fail & err_code;
}
static inline void sd_set_err_code(struct rts51x_chip *chip, u8 err_code)
{
struct sd_info *sd_card = &(chip->sd_card);
sd_card->err_code |= err_code;
}
static inline void sd_clr_err_code(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
sd_card->err_code = 0;
}
static inline int sd_check_err_code(struct rts51x_chip *chip, u8 err_code)
{
struct sd_info *sd_card = &(chip->sd_card);
return sd_card->err_code & err_code;
}
static int sd_parse_err_code(struct rts51x_chip *chip)
{
TRACE_RET(chip, STATUS_FAIL);
}
int sd_check_data0_status(struct rts51x_chip *chip)
{
int retval;
u8 stat;
retval = rts51x_ep0_read_register(chip, SD_BUS_STAT, &stat);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (!(stat & SD_DAT0_STATUS)) {
sd_set_err_code(chip, SD_BUSY);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int timeout = 50;
u16 reg_addr;
u8 buf[17], stat;
int len = 2;
int rty_cnt = 0;
sd_clr_err_code(chip);
RTS51X_DEBUGP("SD/MMC CMD %d, arg = 0x%08x\n", cmd_idx, arg);
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
RTY_SEND_CMD:
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8) (arg >> 24));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8) (arg >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8) (arg >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8) arg);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_CMD_RSP | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END | SD_STAT_IDLE,
SD_TRANSFER_END | SD_STAT_IDLE);
rts51x_add_cmd(chip, READ_REG_CMD, SD_STAT1, 0, 0);
if (CHECK_USB(chip, USB_20)) {
if (rsp_type == SD_RSP_TYPE_R2) {
/* Read data from ping-pong buffer */
for (reg_addr = PPBUF_BASE2;
reg_addr < PPBUF_BASE2 + 16; reg_addr++) {
rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0,
0);
}
len = 18;
} else if (rsp_type != SD_RSP_TYPE_R0) {
/* Read data from SD_CMDx registers */
for (reg_addr = SD_CMD0; reg_addr <= SD_CMD4;
reg_addr++) {
rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0,
0);
}
len = 7;
} else {
len = 2;
}
} else {
len = 2;
}
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, len, timeout);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
u8 val;
rts51x_ep0_read_register(chip, SD_STAT1, &val);
RTS51X_DEBUGP("SD_STAT1: 0x%x\n", val);
rts51x_ep0_read_register(chip, SD_STAT2, &val);
RTS51X_DEBUGP("SD_STAT2: 0x%x\n", val);
if (val & SD_RSP_80CLK_TIMEOUT)
sd_set_err_code(chip, SD_RSP_TIMEOUT);
rts51x_ep0_read_register(chip, SD_BUS_STAT, &val);
RTS51X_DEBUGP("SD_BUS_STAT: 0x%x\n", val);
if (retval == STATUS_TIMEDOUT) {
if (rsp_type & SD_WAIT_BUSY_END) {
retval = sd_check_data0_status(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
sd_set_err_code(chip, SD_TO_ERR);
}
}
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
if (rsp_type == SD_RSP_TYPE_R0)
return STATUS_SUCCESS;
if (CHECK_USB(chip, USB_20)) {
rts51x_read_rsp_buf(chip, 2, buf, len - 2);
} else {
if (rsp_type == SD_RSP_TYPE_R2) {
reg_addr = PPBUF_BASE2;
len = 16;
} else {
reg_addr = SD_CMD0;
len = 5;
}
retval = rts51x_seq_read_register(chip, reg_addr,
(unsigned short)len, buf);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
stat = chip->rsp_buf[1];
/* Check (Start,Transmission) bit of Response */
if ((buf[0] & 0xC0) != 0) {
sd_set_err_code(chip, SD_STS_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
/* Check CRC7 */
if (!(rsp_type & SD_NO_CHECK_CRC7)) {
if (stat & SD_CRC7_ERR) {
if (cmd_idx == WRITE_MULTIPLE_BLOCK) {
sd_set_err_code(chip, SD_CRC_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
if (rty_cnt < SD_MAX_RETRY_COUNT) {
wait_timeout(20);
rty_cnt++;
goto RTY_SEND_CMD;
} else {
sd_set_err_code(chip, SD_CRC_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
}
}
/* Check Status */
if ((rsp_type == SD_RSP_TYPE_R1) || (rsp_type == SD_RSP_TYPE_R1b)) {
if ((cmd_idx != SEND_RELATIVE_ADDR)
&& (cmd_idx != SEND_IF_COND)) {
if (cmd_idx != STOP_TRANSMISSION) {
if (buf[1] & 0x80)
TRACE_RET(chip, STATUS_FAIL);
}
#ifdef SUPPORT_SD_LOCK
/* exclude bit25 CARD_IS_LOCKED */
if (buf[1] & 0x7D) {
#else
if (buf[1] & 0x7F) {
#endif
RTS51X_DEBUGP("buf[1]: 0x%02x\n", buf[1]);
TRACE_RET(chip, STATUS_FAIL);
}
if (buf[2] & 0xFF) {
RTS51X_DEBUGP("buf[2]: 0x%02x\n", buf[2]);
TRACE_RET(chip, STATUS_FAIL);
}
if (buf[3] & 0x80) {
RTS51X_DEBUGP("buf[3]: 0x%02x\n", buf[3]);
TRACE_RET(chip, STATUS_FAIL);
}
if (buf[3] & 0x01) {
/* Get "READY_FOR_DATA" bit */
sd_card->sd_data_buf_ready = 1;
} else {
sd_card->sd_data_buf_ready = 0;
}
}
}
if (rsp && rsp_len)
memcpy(rsp, buf, rsp_len);
return STATUS_SUCCESS;
}
static inline void sd_print_debug_reg(struct rts51x_chip *chip)
{
#ifdef CONFIG_RTS5139_DEBUG
u8 val = 0;
rts51x_ep0_read_register(chip, SD_STAT1, &val);
RTS51X_DEBUGP("SD_STAT1: 0x%x\n", val);
rts51x_ep0_read_register(chip, SD_STAT2, &val);
RTS51X_DEBUGP("SD_STAT2: 0x%x\n", val);
rts51x_ep0_read_register(chip, SD_BUS_STAT, &val);
RTS51X_DEBUGP("SD_BUS_STAT: 0x%x\n", val);
#endif
}
int sd_read_data(struct rts51x_chip *chip, u8 trans_mode, u8 *cmd, int cmd_len,
u16 byte_cnt, u16 blk_cnt, u8 bus_width, u8 *buf, int buf_len,
int timeout)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i;
sd_clr_err_code(chip);
if (!buf)
buf_len = 0;
if (buf_len > 512)
/* This function can't read data more than one page */
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
if (cmd_len) {
RTS51X_DEBUGP("SD/MMC CMD %d\n", cmd[0] - 0x40);
for (i = 0; i < (cmd_len < 6 ? cmd_len : 6); i++) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0 + i, 0xFF,
cmd[i]);
}
}
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8) byte_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF,
(u8) (byte_cnt >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, (u8) blk_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF,
(u8) (blk_cnt >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03, bus_width);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END
| SD_CHECK_CRC7 | SD_RSP_LEN_6);
if (trans_mode != SD_TM_AUTO_TUNING) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
}
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
trans_mode | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END,
SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 1, timeout);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
sd_print_debug_reg(chip);
if (retval == STATUS_TIMEDOUT) {
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
}
TRACE_RET(chip, STATUS_FAIL);
}
if (buf && buf_len) {
retval = rts51x_read_ppbuf(chip, buf, buf_len);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
static int sd_write_data(struct rts51x_chip *chip, u8 trans_mode,
u8 *cmd, int cmd_len, u16 byte_cnt, u16 blk_cnt,
u8 bus_width, u8 *buf, int buf_len, int timeout)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i;
sd_clr_err_code(chip);
if (!buf)
buf_len = 0;
/* This function can't write data more than one page */
if (buf_len > 512)
TRACE_RET(chip, STATUS_FAIL);
if (buf && buf_len) {
retval = rts51x_write_ppbuf(chip, buf, buf_len);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
rts51x_init_cmd(chip);
if (cmd_len) {
RTS51X_DEBUGP("SD/MMC CMD %d\n", cmd[0] - 0x40);
for (i = 0; i < (cmd_len < 6 ? cmd_len : 6); i++) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0 + i, 0xFF,
cmd[i]);
}
}
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8) byte_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF,
(u8) (byte_cnt >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, (u8) blk_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF,
(u8) (blk_cnt >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03, bus_width);
if (cmd_len) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 |
SD_RSP_LEN_6);
}
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
trans_mode | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END,
SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 1, timeout);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
sd_print_debug_reg(chip);
if (retval == STATUS_TIMEDOUT)
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int sd_check_csd(struct rts51x_chip *chip, char check_wp)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i;
u8 csd_ver, trans_speed;
u8 rsp[16];
for (i = 0; i < 6; i++) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
retval =
sd_send_cmd_get_rsp(chip, SEND_CSD, sd_card->sd_addr,
SD_RSP_TYPE_R2, rsp, 16);
if (retval == STATUS_SUCCESS)
break;
}
if (i == 6)
TRACE_RET(chip, STATUS_FAIL);
memcpy(sd_card->raw_csd, rsp + 1, 15);
/* Get CRC7 */
RTS51X_READ_REG(chip, SD_CMD5, sd_card->raw_csd + 15);
RTS51X_DEBUGP("CSD Response:\n");
RTS51X_DUMP(rsp, 16);
/* Get CSD Version */
csd_ver = (rsp[1] & 0xc0) >> 6;
RTS51X_DEBUGP("csd_ver = %d\n", csd_ver);
trans_speed = rsp[4];
if ((trans_speed & 0x07) == 0x02) { /* 10Mbits/s */
if ((trans_speed & 0xf8) >= 0x30) { /* >25Mbits/s */
if (chip->asic_code)
sd_card->sd_clock = 46;
else
sd_card->sd_clock = CLK_50;
} else if ((trans_speed & 0xf8) == 0x28) { /* 20Mbits/s */
if (chip->asic_code)
sd_card->sd_clock = 39;
else
sd_card->sd_clock = CLK_40;
} else if ((trans_speed & 0xf8) == 0x20) { /* 15Mbits/s */
if (chip->asic_code)
sd_card->sd_clock = 29;
else
sd_card->sd_clock = CLK_30;
} else if ((trans_speed & 0xf8) >= 0x10) { /* 12Mbits/s */
if (chip->asic_code)
sd_card->sd_clock = 23;
else
sd_card->sd_clock = CLK_20;
} else if ((trans_speed & 0x08) >= 0x08) { /* 10Mbits/s */
if (chip->asic_code)
sd_card->sd_clock = 19;
else
sd_card->sd_clock = CLK_20;
} /*else { */
/*If this ,then slow card will use 30M clock */
/* TRACE_RET(chip, STATUS_FAIL); */
/* } */
}
/*else {
TRACE_RET(chip, STATUS_FAIL);
} */
if (CHK_MMC_SECTOR_MODE(sd_card)) {
sd_card->capacity = 0;
} else {
/* For High-Capacity Card, CSD_STRUCTURE always be "0x1" */
if ((!CHK_SD_HCXC(sd_card)) || (csd_ver == 0)) {
/* Calculate total sector according to C_SIZE,
* C_SIZE_MULT & READ_BL_LEN */
u8 blk_size, c_size_mult;
u16 c_size;
/* Get READ_BL_LEN */
blk_size = rsp[6] & 0x0F;
/* Get C_SIZE */
c_size = ((u16) (rsp[7] & 0x03) << 10)
+ ((u16) rsp[8] << 2)
+ ((u16) (rsp[9] & 0xC0) >> 6);
/* Get C_SIZE_MUL */
c_size_mult = (u8) ((rsp[10] & 0x03) << 1);
c_size_mult += (rsp[11] & 0x80) >> 7;
/* Calculate total Capacity */
sd_card->capacity =
(((u32) (c_size + 1)) *
(1 << (c_size_mult + 2))) << (blk_size - 9);
} else {
/* High Capacity Card and Use CSD2.0 Version */
u32 total_sector = 0;
total_sector = (((u32) rsp[8] & 0x3f) << 16) |
((u32) rsp[9] << 8) | (u32) rsp[10];
/* Total Capacity= (C_SIZE+1) *
* 512K Byte = (C_SIZE+1)K Sector,1K = 1024 Bytes */
sd_card->capacity = (total_sector + 1) << 10;
}
}
/* We need check Write-Protected Status by Field PERM WP or TEMP WP */
if (check_wp) {
if (rsp[15] & 0x30)
chip->card_wp |= SD_CARD;
RTS51X_DEBUGP("CSD WP Status: 0x%x\n", rsp[15]);
}
return STATUS_SUCCESS;
}
static int sd_set_sample_push_timing(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
rts51x_init_cmd(chip);
if (CHK_SD_SDR104(sd_card) || CHK_SD_SDR50(sd_card)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1,
0x0C | SD_ASYNC_FIFO_RST,
SD_30_MODE | SD_ASYNC_FIFO_RST);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
} else if (CHK_SD_DDR50(sd_card) || CHK_MMC_DDR52(sd_card)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1,
0x0C | SD_ASYNC_FIFO_RST,
SD_DDR_MODE | SD_ASYNC_FIFO_RST);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
DDR_VAR_RX_DAT | DDR_VAR_RX_CMD,
DDR_VAR_RX_DAT | DDR_VAR_RX_CMD);
} else {
u8 val = 0;
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x0C, SD_20_MODE);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF,
CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1);
if ((chip->option.sd_ctl & SD_PUSH_POINT_CTL_MASK) ==
SD_PUSH_POINT_AUTO) {
val = SD20_TX_NEG_EDGE;
} else if ((chip->option.sd_ctl & SD_PUSH_POINT_CTL_MASK) ==
SD_PUSH_POINT_DELAY) {
val = SD20_TX_14_AHEAD;
} else {
val = SD20_TX_NEG_EDGE;
}
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_PUSH_POINT_CTL,
SD20_TX_SEL_MASK, val);
if ((chip->option.sd_ctl & SD_SAMPLE_POINT_CTL_MASK) ==
SD_SAMPLE_POINT_AUTO) {
if (chip->asic_code) {
if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card))
val = SD20_RX_14_DELAY;
else
val = SD20_RX_POS_EDGE;
} else {
val = SD20_RX_14_DELAY;
}
} else if ((chip->option.sd_ctl & SD_SAMPLE_POINT_CTL_MASK) ==
SD_SAMPLE_POINT_DELAY) {
val = SD20_RX_14_DELAY;
} else {
val = SD20_RX_POS_EDGE;
}
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL,
SD20_RX_SEL_MASK, val);
}
if (CHK_MMC_DDR52(sd_card) && CHK_MMC_8BIT(sd_card)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
EXTEND_DMA1_ASYNC_SIGNAL, 0);
}
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static void sd_choose_proper_clock(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
if (CHK_SD_SDR104(sd_card)) {
if (chip->asic_code)
sd_card->sd_clock = chip->option.asic_sd_sdr104_clk;
else
sd_card->sd_clock = chip->option.fpga_sd_sdr104_clk;
} else if (CHK_SD_DDR50(sd_card)) {
if (chip->asic_code)
sd_card->sd_clock = chip->option.asic_sd_ddr50_clk;
else
sd_card->sd_clock = chip->option.fpga_sd_ddr50_clk;
} else if (CHK_SD_SDR50(sd_card)) {
if (chip->asic_code)
sd_card->sd_clock = chip->option.asic_sd_sdr50_clk;
else
sd_card->sd_clock = chip->option.fpga_sd_sdr50_clk;
} else if (CHK_SD_HS(sd_card)) {
if (chip->asic_code)
sd_card->sd_clock = chip->option.asic_sd_hs_clk;
else
sd_card->sd_clock = chip->option.fpga_sd_hs_clk;
} else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) {
if (chip->asic_code)
sd_card->sd_clock = chip->option.asic_mmc_52m_clk;
else
sd_card->sd_clock = chip->option.fpga_mmc_52m_clk;
} else if (CHK_MMC_26M(sd_card)) {
if (chip->asic_code) {
sd_card->sd_clock = 46;
RTS51X_DEBUGP("Set MMC clock to 22.5MHz\n");
} else {
sd_card->sd_clock = CLK_50;
}
}
}
static int sd_set_init_para(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
retval = sd_set_sample_push_timing(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
sd_choose_proper_clock(chip);
retval = switch_clock(chip, sd_card->sd_clock);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int sd_select_card(struct rts51x_chip *chip, int select)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 cmd_idx, cmd_type;
u32 addr;
if (select) {
cmd_idx = SELECT_CARD;
cmd_type = SD_RSP_TYPE_R1;
addr = sd_card->sd_addr;
} else {
cmd_idx = DESELECT_CARD;
cmd_type = SD_RSP_TYPE_R0;
addr = 0;
}
retval = sd_send_cmd_get_rsp(chip, cmd_idx, addr, cmd_type, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
#ifdef SUPPORT_SD_LOCK
int sd_update_lock_status(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 rsp[5];
retval =
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, rsp, 5);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
if (rsp[1] & 0x02)
sd_card->sd_lock_status |= SD_LOCKED;
else
sd_card->sd_lock_status &= ~SD_LOCKED;
RTS51X_DEBUGP("sd_card->sd_lock_status = 0x%x\n",
sd_card->sd_lock_status);
if (rsp[1] & 0x01) {
/* LOCK_UNLOCK_FAILED */
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
#endif
int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
u8 rdychk, u16 pollingcnt)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 rsp[5];
u16 i;
for (i = 0; i < pollingcnt; i++) {
retval =
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, rsp, 5);
if (retval == STATUS_SUCCESS) {
if (((rsp[3] & 0x1E) == statechk)
&& ((rsp[3] & 0x01) == rdychk)) {
return STATUS_SUCCESS;
}
} else {
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
}
return STATUS_TIMEDOUT;
}
static int sd_voltage_switch(struct rts51x_chip *chip)
{
int retval;
u8 stat;
RTS51X_WRITE_REG(chip, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP,
SD_CLK_TOGGLE_EN);
retval =
sd_send_cmd_get_rsp(chip, VOLTAGE_SWITCH, 0, SD_RSP_TYPE_R1, NULL,
0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_READ_REG(chip, SD_BUS_STAT, &stat);
if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS |
SD_DAT1_STATUS | SD_DAT0_STATUS))
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BUS_STAT, 0xFF,
SD_CLK_FORCE_STOP);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_PAD_CTL, SD_IO_USING_1V8,
SD_IO_USING_1V8);
if (chip->asic_code)
rts51x_add_cmd(chip, WRITE_REG_CMD, LDO_POWER_CFG,
TUNE_SD18_MASK, TUNE_SD18_1V8);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
wait_timeout(chip->option.D3318_off_delay);
RTS51X_WRITE_REG(chip, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN);
wait_timeout(10);
RTS51X_READ_REG(chip, SD_BUS_STAT, &stat);
if ((stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS |
SD_DAT1_STATUS | SD_DAT0_STATUS)) !=
(SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS |
SD_DAT1_STATUS | SD_DAT0_STATUS)) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BUS_STAT, 0xFF,
SD_CLK_FORCE_STOP);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, 0xFF, 0);
rts51x_send_cmd(chip, MODE_C, 100);
TRACE_RET(chip, STATUS_FAIL);
}
RTS51X_WRITE_REG(chip, SD_BUS_STAT,
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
return STATUS_SUCCESS;
}
static int sd_change_phase(struct rts51x_chip *chip, u8 sample_point,
u8 tune_dir)
{
u16 SD_VP_CTL, SD_DCMPS_CTL;
u8 val;
int retval;
RTS51X_DEBUGP("sd_change_phase (sample_point = %d, tune_dir = %d)\n",
sample_point, tune_dir);
if (tune_dir == TUNE_RX) {
SD_VP_CTL = SD_VPCLK1_CTL;
SD_DCMPS_CTL = SD_DCMPS1_CTL;
} else {
SD_VP_CTL = SD_VPCLK0_CTL;
SD_DCMPS_CTL = SD_DCMPS0_CTL;
}
if (chip->asic_code) {
RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
RTS51X_WRITE_REG(chip, SD_VP_CTL, 0x1F, sample_point);
RTS51X_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
RTS51X_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET,
PHASE_NOT_RESET);
RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, 0);
} else {
#ifdef CONFIG_RTS5139_DEBUG
RTS51X_READ_REG(chip, SD_VP_CTL, &val);
RTS51X_DEBUGP("SD_VP_CTL: 0x%x\n", val);
RTS51X_READ_REG(chip, SD_DCMPS_CTL, &val);
RTS51X_DEBUGP("SD_DCMPS_CTL: 0x%x\n", val);
#endif
RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
udelay(100);
RTS51X_WRITE_REG(chip, SD_VP_CTL, 0xFF,
PHASE_NOT_RESET | sample_point);
udelay(200);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_DCMPS_CTL, DCMPS_CHANGE,
DCMPS_CHANGE);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_DCMPS_CTL,
DCMPS_CHANGE_DONE, DCMPS_CHANGE_DONE);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, Fail);
retval = rts51x_get_rsp(chip, 1, 500);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, Fail);
val = chip->rsp_buf[0];
if (val & DCMPS_ERROR)
TRACE_GOTO(chip, Fail);
if ((val & DCMPS_CURRENT_PHASE) != sample_point)
TRACE_GOTO(chip, Fail);
RTS51X_WRITE_REG(chip, SD_DCMPS_CTL, DCMPS_CHANGE, 0);
RTS51X_WRITE_REG(chip, CLK_DIV, CLK_CHANGE, 0);
udelay(100);
}
RTS51X_WRITE_REG(chip, SD_CFG1, SD_ASYNC_FIFO_RST, 0);
return STATUS_SUCCESS;
Fail:
#ifdef CONFIG_RTS5139_DEBUG
rts51x_ep0_read_register(chip, SD_VP_CTL, &val);
RTS51X_DEBUGP("SD_VP_CTL: 0x%x\n", val);
rts51x_ep0_read_register(chip, SD_DCMPS_CTL, &val);
RTS51X_DEBUGP("SD_DCMPS_CTL: 0x%x\n", val);
#endif
RTS51X_WRITE_REG(chip, SD_DCMPS_CTL, DCMPS_CHANGE, 0);
RTS51X_WRITE_REG(chip, SD_VP_CTL, PHASE_CHANGE, 0);
wait_timeout(10);
return STATUS_FAIL;
}
static int sd_check_spec(struct rts51x_chip *chip, u8 bus_width)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 cmd[5], buf[8];
retval =
sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
cmd[0] = 0x40 | SEND_SCR;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[4] = 0;
retval =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 8, 1, bus_width, buf,
8, 250);
if (retval != STATUS_SUCCESS) {
rts51x_clear_sd_error(chip);
TRACE_RET(chip, retval);
}
memcpy(sd_card->raw_scr, buf, 8);
if ((buf[0] & 0x0F) == 0)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
static int sd_query_switch_result(struct rts51x_chip *chip, u8 func_group,
u8 func_to_switch, u8 *buf, int buf_len)
{
u8 support_mask = 0, query_switch = 0, switch_busy = 0;
int support_offset = 0, query_switch_offset = 0, check_busy_offset = 0;
if (func_group == SD_FUNC_GROUP_1) {
support_offset = FUNCTION_GROUP1_SUPPORT_OFFSET;
query_switch_offset = FUNCTION_GROUP1_QUERY_SWITCH_OFFSET;
check_busy_offset = FUNCTION_GROUP1_CHECK_BUSY_OFFSET;
switch (func_to_switch) {
case HS_SUPPORT:
support_mask = HS_SUPPORT_MASK;
query_switch = HS_QUERY_SWITCH_OK;
switch_busy = HS_SWITCH_BUSY;
break;
case SDR50_SUPPORT:
support_mask = SDR50_SUPPORT_MASK;
query_switch = SDR50_QUERY_SWITCH_OK;
switch_busy = SDR50_SWITCH_BUSY;
break;
case SDR104_SUPPORT:
support_mask = SDR104_SUPPORT_MASK;
query_switch = SDR104_QUERY_SWITCH_OK;
switch_busy = SDR104_SWITCH_BUSY;
break;
case DDR50_SUPPORT:
support_mask = DDR50_SUPPORT_MASK;
query_switch = DDR50_QUERY_SWITCH_OK;
switch_busy = DDR50_SWITCH_BUSY;
break;
default:
TRACE_RET(chip, STATUS_FAIL);
}
} else if (func_group == SD_FUNC_GROUP_3) {
support_offset = FUNCTION_GROUP3_SUPPORT_OFFSET;
query_switch_offset = FUNCTION_GROUP3_QUERY_SWITCH_OFFSET;
check_busy_offset = FUNCTION_GROUP3_CHECK_BUSY_OFFSET;
switch (func_to_switch) {
case DRIVING_TYPE_A:
support_mask = DRIVING_TYPE_A_MASK;
query_switch = TYPE_A_QUERY_SWITCH_OK;
switch_busy = TYPE_A_SWITCH_BUSY;
break;
case DRIVING_TYPE_C:
support_mask = DRIVING_TYPE_C_MASK;
query_switch = TYPE_C_QUERY_SWITCH_OK;
switch_busy = TYPE_C_SWITCH_BUSY;
break;
case DRIVING_TYPE_D:
support_mask = DRIVING_TYPE_D_MASK;
query_switch = TYPE_D_QUERY_SWITCH_OK;
switch_busy = TYPE_D_SWITCH_BUSY;
break;
default:
TRACE_RET(chip, STATUS_FAIL);
}
} else if (func_group == SD_FUNC_GROUP_4) {
support_offset = FUNCTION_GROUP4_SUPPORT_OFFSET;
query_switch_offset = FUNCTION_GROUP4_QUERY_SWITCH_OFFSET;
check_busy_offset = FUNCTION_GROUP4_CHECK_BUSY_OFFSET;
switch (func_to_switch) {
case CURRENT_LIMIT_400:
support_mask = CURRENT_LIMIT_400_MASK;
query_switch = CURRENT_LIMIT_400_QUERY_SWITCH_OK;
switch_busy = CURRENT_LIMIT_400_SWITCH_BUSY;
break;
case CURRENT_LIMIT_600:
support_mask = CURRENT_LIMIT_600_MASK;
query_switch = CURRENT_LIMIT_600_QUERY_SWITCH_OK;
switch_busy = CURRENT_LIMIT_600_SWITCH_BUSY;
break;
case CURRENT_LIMIT_800:
support_mask = CURRENT_LIMIT_800_MASK;
query_switch = CURRENT_LIMIT_800_QUERY_SWITCH_OK;
switch_busy = CURRENT_LIMIT_800_SWITCH_BUSY;
break;
default:
TRACE_RET(chip, STATUS_FAIL);
}
} else {
TRACE_RET(chip, STATUS_FAIL);
}
if (func_group == SD_FUNC_GROUP_4)
buf[query_switch_offset] =
(buf[query_switch_offset] & 0xf0) >> 4;
if (!(buf[support_offset] & support_mask) ||
((buf[query_switch_offset] & 0x0F) != query_switch))
TRACE_RET(chip, STATUS_FAIL);
if ((buf[DATA_STRUCTURE_VER_OFFSET] == 0x01) &&
((buf[check_busy_offset] & switch_busy) == switch_busy))
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
static int sd_check_switch_mode(struct rts51x_chip *chip, u8 mode,
u8 func_group, u8 func_to_switch, u8 bus_width)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 cmd[5], buf[64];
RTS51X_DEBUGP("sd_check_switch_mode (mode = %d, func_group = %d,"
"func_to_switch = %d)\n", mode, func_group, func_to_switch);
cmd[0] = 0x40 | SWITCH;
cmd[1] = mode;
if (func_group == SD_FUNC_GROUP_1) {
cmd[2] = 0xFF;
cmd[3] = 0xFF;
cmd[4] = 0xF0 + func_to_switch;
} else if (func_group == SD_FUNC_GROUP_3) {
cmd[2] = 0xFF;
cmd[3] = 0xF0 + func_to_switch;
cmd[4] = 0xFF;
} else if (func_group == SD_FUNC_GROUP_4) {
cmd[2] = 0xFF;
cmd[3] = 0x0F + (func_to_switch << 4);
cmd[4] = 0xFF;
} else {
cmd[1] = SD_CHECK_MODE;
cmd[2] = 0xFF;
cmd[3] = 0xFF;
cmd[4] = 0xFF;
}
retval =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 64, 1, bus_width, buf,
64, 250);
if (retval != STATUS_SUCCESS) {
rts51x_clear_sd_error(chip);
TRACE_RET(chip, retval);
}
if (func_group == NO_ARGUMENT) {
sd_card->func_group1_mask = buf[0x0D];
sd_card->func_group2_mask = buf[0x0B];
sd_card->func_group3_mask = buf[0x09];
sd_card->func_group4_mask = buf[0x07];
RTS51X_DEBUGP("func_group1_mask = 0x%02x\n", buf[0x0D]);
RTS51X_DEBUGP("func_group2_mask = 0x%02x\n", buf[0x0B]);
RTS51X_DEBUGP("func_group3_mask = 0x%02x\n", buf[0x09]);
RTS51X_DEBUGP("func_group4_mask = 0x%02x\n", buf[0x07]);
} else {
if ((buf[0] == 0) && (buf[1] == 0))
TRACE_RET(chip, STATUS_FAIL);
retval =
sd_query_switch_result(chip, func_group, func_to_switch,
buf, 64);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
static int sd_check_switch(struct rts51x_chip *chip,
u8 func_group, u8 func_to_switch, u8 bus_width)
{
int retval;
int i;
int switch_good = 0;
for (i = 0; i < 3; i++) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
retval = sd_check_switch_mode(chip, SD_CHECK_MODE, func_group,
func_to_switch, bus_width);
if (retval == STATUS_SUCCESS) {
u8 stat;
retval = sd_check_switch_mode(chip, SD_SWITCH_MODE,
func_group, func_to_switch, bus_width);
if (retval == STATUS_SUCCESS) {
switch_good = 1;
break;
}
RTS51X_READ_REG(chip, SD_STAT1, &stat);
if (stat & SD_CRC16_ERR) {
RTS51X_DEBUGP("SD CRC16 error when switching"
"mode\n");
TRACE_RET(chip, STATUS_FAIL);
}
}
wait_timeout(20);
}
if (!switch_good)
TRACE_RET(chip, STATUS_FAIL);
return STATUS_SUCCESS;
}
static int sd_switch_function(struct rts51x_chip *chip, u8 bus_width)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i;
u8 func_to_switch = 0;
/* Get supported functions */
retval = sd_check_switch_mode(chip, SD_CHECK_MODE,
NO_ARGUMENT, NO_ARGUMENT, bus_width);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
sd_card->func_group1_mask &= ~(sd_card->sd_switch_fail);
for (i = 0; i < 4; i++) {
switch ((u8) (chip->option.sd_speed_prior >> (i * 8))) {
case DDR50_SUPPORT:
if ((sd_card->func_group1_mask & DDR50_SUPPORT_MASK)
&& (CHECK_UHS50(chip)))
func_to_switch = DDR50_SUPPORT;
break;
case SDR50_SUPPORT:
if ((sd_card->func_group1_mask & SDR50_SUPPORT_MASK)
&& (CHECK_UHS50(chip)))
func_to_switch = SDR50_SUPPORT;
break;
case HS_SUPPORT:
if (sd_card->func_group1_mask & HS_SUPPORT_MASK)
func_to_switch = HS_SUPPORT;
break;
default:
continue;
}
if (func_to_switch)
break;
}
RTS51X_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x",
func_to_switch);
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_SDR_RST)
&& (DDR50_SUPPORT == func_to_switch)
&& (sd_card->func_group1_mask & SDR50_SUPPORT_MASK)) {
func_to_switch = SDR50_SUPPORT;
RTS51X_DEBUGP("Using SDR50 instead of DDR50 for SD Lock\n");
}
#endif
if (func_to_switch) {
retval =
sd_check_switch(chip, SD_FUNC_GROUP_1, func_to_switch,
bus_width);
if (retval != STATUS_SUCCESS) {
if (func_to_switch == SDR104_SUPPORT)
sd_card->sd_switch_fail = SDR104_SUPPORT_MASK;
else if (func_to_switch == DDR50_SUPPORT)
sd_card->sd_switch_fail = DDR50_SUPPORT_MASK;
else if (func_to_switch == SDR50_SUPPORT)
sd_card->sd_switch_fail = SDR50_SUPPORT_MASK;
else if (func_to_switch == HS_SUPPORT)
sd_card->sd_switch_fail = HS_SUPPORT_MASK;
TRACE_RET(chip, retval);
}
if (func_to_switch == SDR104_SUPPORT)
SET_SD_SDR104(sd_card);
else if (func_to_switch == DDR50_SUPPORT)
SET_SD_DDR50(sd_card);
else if (func_to_switch == SDR50_SUPPORT)
SET_SD_SDR50(sd_card);
else
SET_SD_HS(sd_card);
}
if (CHK_SD_DDR50(sd_card))
RTS51X_WRITE_REG(chip, SD_CFG1, 0x0C, SD_DDR_MODE);
func_to_switch = 0;
if (sd_card->func_group4_mask & CURRENT_LIMIT_400_MASK)
func_to_switch = CURRENT_LIMIT_400;
if (func_to_switch) {
RTS51X_DEBUGP("Try to switch current_limit_400\n");
retval =
sd_check_switch(chip, SD_FUNC_GROUP_4, func_to_switch,
bus_width);
RTS51X_DEBUGP("Switch current_limit_400 status: (%d)\n",
retval);
}
return STATUS_SUCCESS;
}
static int sd_wait_data_idle(struct rts51x_chip *chip)
{
int retval = STATUS_TIMEDOUT;
int i;
u8 val = 0;
for (i = 0; i < 100; i++) {
retval = rts51x_ep0_read_register(chip, SD_DATA_STATE, &val);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
if (val & SD_DATA_IDLE) {
retval = STATUS_SUCCESS;
break;
}
udelay(100);
}
RTS51X_DEBUGP("SD_DATA_STATE: 0x%02x\n", val);
return retval;
}
static int sd_sdr_tuning_rx_cmd(struct rts51x_chip *chip, u8 sample_point)
{
int retval;
u8 cmd[5];
retval = sd_change_phase(chip, sample_point, TUNE_RX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
cmd[0] = 0x40 | SEND_TUNING_PATTERN;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[4] = 0;
retval = sd_read_data(chip, SD_TM_AUTO_TUNING,
cmd, 5, 0x40, 1, SD_BUS_WIDTH_4, NULL, 0, 100);
if (retval != STATUS_SUCCESS) {
/* Wait till SD DATA IDLE */
(void)sd_wait_data_idle(chip);
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int sd_ddr_tuning_rx_cmd(struct rts51x_chip *chip, u8 sample_point)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 cmd[5];
retval = sd_change_phase(chip, sample_point, TUNE_RX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_DEBUGP("sd ddr tuning rx\n");
retval =
sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
cmd[0] = 0x40 | SD_STATUS;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[4] = 0;
retval = sd_read_data(chip, SD_TM_NORMAL_READ,
cmd, 5, 64, 1, SD_BUS_WIDTH_4, NULL, 0, 100);
if (retval != STATUS_SUCCESS) {
/* Wait till SD DATA IDLE */
(void)sd_wait_data_idle(chip);
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int mmc_ddr_tunning_rx_cmd(struct rts51x_chip *chip, u8 sample_point)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 cmd[5], bus_width;
if (CHK_MMC_8BIT(sd_card))
bus_width = SD_BUS_WIDTH_8;
else if (CHK_MMC_4BIT(sd_card))
bus_width = SD_BUS_WIDTH_4;
else
bus_width = SD_BUS_WIDTH_1;
retval = sd_change_phase(chip, sample_point, TUNE_RX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_DEBUGP("mmc ddr tuning rx\n");
cmd[0] = 0x40 | SEND_EXT_CSD;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[4] = 0;
retval = sd_read_data(chip, SD_TM_NORMAL_READ,
cmd, 5, 0x200, 1, bus_width, NULL, 0, 100);
if (retval != STATUS_SUCCESS) {
/* Wait till SD DATA IDLE */
(void)sd_wait_data_idle(chip);
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int sd_sdr_tuning_tx_cmd(struct rts51x_chip *chip, u8 sample_point)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
retval = sd_change_phase(chip, sample_point, TUNE_TX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
if (retval != STATUS_SUCCESS) {
if (sd_check_err_code(chip, SD_RSP_TIMEOUT)) {
/* Tunning TX fail */
rts51x_ep0_write_register(chip, SD_CFG3,
SD_RSP_80CLK_TIMEOUT_EN, 0);
TRACE_RET(chip, STATUS_FAIL);
}
}
RTS51X_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0);
return STATUS_SUCCESS;
}
static int sd_ddr_tuning_tx_cmd(struct rts51x_chip *chip, u8 sample_point)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 cmd[5], bus_width;
retval = sd_change_phase(chip, sample_point, TUNE_TX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (CHK_SD(sd_card)) {
bus_width = SD_BUS_WIDTH_4;
} else {
if (CHK_MMC_8BIT(sd_card))
bus_width = SD_BUS_WIDTH_8;
else if (CHK_MMC_4BIT(sd_card))
bus_width = SD_BUS_WIDTH_4;
else
bus_width = SD_BUS_WIDTH_1;
}
retval = sd_wait_currentstate_dataready(chip, 0x08, 1, 20);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
RTS51X_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
cmd[0] = 0x40 | PROGRAM_CSD;
cmd[1] = 0;
cmd[2] = 0;
cmd[3] = 0;
cmd[4] = 0;
retval = sd_write_data(chip, SD_TM_AUTO_WRITE_2,
cmd, 5, 16, 1, bus_width, sd_card->raw_csd, 16, 100);
if (retval != STATUS_SUCCESS) {
rts51x_clear_sd_error(chip);
/* Tunning TX fail */
rts51x_ep0_write_register(chip, SD_CFG3,
SD_RSP_80CLK_TIMEOUT_EN, 0);
TRACE_RET(chip, STATUS_FAIL);
}
RTS51X_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0);
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
return STATUS_SUCCESS;
}
static u8 sd_search_final_phase(struct rts51x_chip *chip, u32 phase_map,
u8 tune_dir)
{
struct sd_info *sd_card = &(chip->sd_card);
struct timing_phase_path path[MAX_PHASE + 1];
int i, j, cont_path_cnt;
int new_block, max_len;
u8 final_phase = 0xFF;
int final_path_idx;
if (phase_map == 0xffff) {
if (CHK_SD_DDR50(sd_card)) {
if (tune_dir == TUNE_TX)
final_phase = chip->option.ddr50_tx_phase;
else
final_phase = chip->option.ddr50_rx_phase;
RTS51X_DEBUGP("DDR50 tuning dir:%d all pass,"
"so select default phase:0x%x.\n",
tune_dir, final_phase);
} else {
if (tune_dir == TUNE_TX)
final_phase = chip->option.sdr50_tx_phase;
else
final_phase = chip->option.sdr50_rx_phase;
RTS51X_DEBUGP("SDR50 tuning dir:%d all pass,"
"so select default phase:0x%x.\n",
tune_dir, final_phase);
}
goto Search_Finish;
}
cont_path_cnt = 0;
new_block = 1;
j = 0;
for (i = 0; i < MAX_PHASE + 1; i++) {
if (phase_map & (1 << i)) {
if (new_block) {
new_block = 0;
j = cont_path_cnt++;
path[j].start = i;
path[j].end = i;
} else {
path[j].end = i;
}
} else {
new_block = 1;
if (cont_path_cnt) {
int idx = cont_path_cnt - 1;
path[idx].len =
path[idx].end - path[idx].start + 1;
path[idx].mid =
path[idx].start + path[idx].len / 2;
}
}
}
if (cont_path_cnt == 0) {
RTS51X_DEBUGP("No continuous phase path\n");
goto Search_Finish;
} else {
int idx = cont_path_cnt - 1;
path[idx].len = path[idx].end - path[idx].start + 1;
path[idx].mid = path[idx].start + path[idx].len / 2;
}
if ((path[0].start == 0) &&
(path[cont_path_cnt - 1].end == MAX_PHASE)) {
path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1;
path[0].len += path[cont_path_cnt - 1].len;
path[0].mid = path[0].start + path[0].len / 2;
if (path[0].mid < 0)
path[0].mid += MAX_PHASE + 1;
cont_path_cnt--;
}
max_len = 0;
final_phase = 0;
final_path_idx = 0;
for (i = 0; i < cont_path_cnt; i++) {
if (path[i].len > max_len) {
max_len = path[i].len;
final_phase = (u8) path[i].mid;
final_path_idx = i;
}
RTS51X_DEBUGP("path[%d].start = %d\n", i, path[i].start);
RTS51X_DEBUGP("path[%d].end = %d\n", i, path[i].end);
RTS51X_DEBUGP("path[%d].len = %d\n", i, path[i].len);
RTS51X_DEBUGP("path[%d].mid = %d\n", i, path[i].mid);
RTS51X_DEBUGP("\n");
}
if ((tune_dir == TUNE_TX) && (CHK_SD_SDR50(sd_card))
&& chip->option.sdr50_phase_sel) {
if (max_len > 6) {
int temp_mid = (max_len - 6) / 2;
int temp_final_phase =
path[final_path_idx].end - (max_len -
(3 + temp_mid));
if (temp_final_phase < 0)
final_phase = temp_final_phase + MAX_PHASE + 1;
else
final_phase = (u8) temp_final_phase;
}
}
Search_Finish:
RTS51X_DEBUGP("Final choosen phase: %d\n", final_phase);
return final_phase;
}
static int sd_tuning_rx(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i, j;
u32 raw_phase_map[3], phase_map;
u8 final_phase;
int (*tuning_cmd) (struct rts51x_chip *chip, u8 sample_point);
if (CHK_SD(sd_card)) {
if (CHK_SD_DDR50(sd_card))
tuning_cmd = sd_ddr_tuning_rx_cmd;
else
tuning_cmd = sd_sdr_tuning_rx_cmd;
} else {
if (CHK_MMC_DDR52(sd_card))
tuning_cmd = mmc_ddr_tunning_rx_cmd;
else
TRACE_RET(chip, STATUS_FAIL);
}
for (i = 0; i < 3; i++) {
raw_phase_map[i] = 0;
for (j = MAX_PHASE; j >= 0; j--) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
retval = tuning_cmd(chip, (u8) j);
if (retval == STATUS_SUCCESS)
raw_phase_map[i] |= 1 << j;
else
RTS51X_DEBUGP("Tuning phase %d fail\n", j);
}
}
phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2];
for (i = 0; i < 3; i++)
RTS51X_DEBUGP("RX raw_phase_map[%d] = 0x%04x\n", i,
raw_phase_map[i]);
RTS51X_DEBUGP("RX phase_map = 0x%04x\n", phase_map);
final_phase = sd_search_final_phase(chip, phase_map, TUNE_RX);
if (final_phase == 0xFF)
TRACE_RET(chip, STATUS_FAIL);
retval = tuning_cmd(chip, final_phase);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static int sd_ddr_pre_tuning_tx(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 i;
u8 pre_tune_tx_phase;
u32 pre_tune_phase_map;
RTS51X_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN,
SD_RSP_80CLK_TIMEOUT_EN);
pre_tune_tx_phase = 0xFF;
pre_tune_phase_map = 0x0000;
for (i = 0; i < MAX_PHASE + 1; i++) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
retval = sd_change_phase(chip, (u8) i, TUNE_TX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval =
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
if ((retval == STATUS_SUCCESS)
|| !sd_check_err_code(chip, SD_RSP_TIMEOUT))
pre_tune_phase_map |= (u32) 1 << i;
}
RTS51X_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0);
pre_tune_tx_phase =
sd_search_final_phase(chip, pre_tune_phase_map, TUNE_TX);
if (pre_tune_tx_phase == 0xFF)
TRACE_RET(chip, STATUS_FAIL);
sd_change_phase(chip, pre_tune_tx_phase, TUNE_TX);
RTS51X_DEBUGP("DDR TX pre tune phase: %d\n", (int)pre_tune_tx_phase);
return STATUS_SUCCESS;
}
static int sd_tuning_tx(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i, j;
u32 raw_phase_map[3], phase_map;
u8 final_phase;
int (*tuning_cmd) (struct rts51x_chip *chip, u8 sample_point);
if (CHK_SD(sd_card)) {
if (CHK_SD_DDR50(sd_card))
tuning_cmd = sd_ddr_tuning_tx_cmd;
else
tuning_cmd = sd_sdr_tuning_tx_cmd;
} else {
if (CHK_MMC_DDR52(sd_card))
tuning_cmd = sd_ddr_tuning_tx_cmd;
else
TRACE_RET(chip, STATUS_FAIL);
}
for (i = 0; i < 3; i++) {
raw_phase_map[i] = 0;
for (j = MAX_PHASE; j >= 0; j--) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
retval = tuning_cmd(chip, (u8) j);
if (retval == STATUS_SUCCESS)
raw_phase_map[i] |= 1 << j;
else
RTS51X_DEBUGP("Tuning phase %d fail\n", j);
}
}
phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2];
for (i = 0; i < 3; i++)
RTS51X_DEBUGP("TX raw_phase_map[%d] = 0x%04x\n", i,
raw_phase_map[i]);
RTS51X_DEBUGP("TX phase_map = 0x%04x\n", phase_map);
final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX);
if (final_phase == 0xFF)
TRACE_RET(chip, STATUS_FAIL);
retval = tuning_cmd(chip, final_phase);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static int sd_sdr_tuning(struct rts51x_chip *chip)
{
int retval;
retval = sd_tuning_tx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = sd_tuning_rx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static int sd_ddr_tuning(struct rts51x_chip *chip)
{
int retval;
if (!(chip->option.sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_ddr_pre_tuning_tx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
retval =
sd_change_phase(chip, (u8) chip->option.sd_ddr_tx_phase,
TUNE_TX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
retval = sd_tuning_rx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (!(chip->option.sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_tuning_tx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
static int mmc_ddr_tuning(struct rts51x_chip *chip)
{
int retval;
if (!(chip->option.sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_ddr_pre_tuning_tx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
retval =
sd_change_phase(chip, (u8) chip->option.mmc_ddr_tx_phase,
TUNE_TX);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
retval = sd_tuning_rx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (!(chip->option.sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) {
retval = sd_tuning_tx(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
int sd_switch_clock(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int re_tuning = 0;
retval = rts51x_select_card(chip, SD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (CHK_SD30_SPEED(sd_card) || CHK_MMC_DDR52(sd_card)) {
if (sd_card->sd_clock != chip->cur_clk)
re_tuning = 1;
}
retval = switch_clock(chip, sd_card->sd_clock);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (re_tuning) {
if (CHK_SD(sd_card)) {
if (CHK_SD_DDR50(sd_card))
retval = sd_ddr_tuning(chip);
else
retval = sd_sdr_tuning(chip);
} else {
if (CHK_MMC_DDR52(sd_card))
retval = mmc_ddr_tuning(chip);
}
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
static int sd_prepare_reset(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
if (chip->asic_code)
sd_card->sd_clock = 29;
else
sd_card->sd_clock = CLK_30;
/* Set SD Clocks */
retval = sd_set_init_para(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0xFF,
SD_CLK_DIVIDE_128 | SD_20_MODE | SD_BUS_WIDTH_1);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, 0xFF,
SD20_RX_POS_EDGE);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_PUSH_POINT_CTL, 0xFF, 0);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_select_card(chip, SD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static void sd_pull_ctl_disable(struct rts51x_chip *chip)
{
if (CHECK_PKG(chip, LQFP48)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
}
}
static void sd_pull_ctl_enable(struct rts51x_chip *chip)
{
if (CHECK_PKG(chip, LQFP48)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xAA);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0xAA);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA9);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xA5);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x9A);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA5);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x9A);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x65);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x5A);
}
}
static int sd_init_power(struct rts51x_chip *chip)
{
int retval;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, LDO3318_PWR_MASK,
LDO_ON);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_PAD_CTL, SD_IO_USING_1V8,
SD_IO_USING_3V3);
if (chip->asic_code)
rts51x_add_cmd(chip, WRITE_REG_CMD, LDO_POWER_CFG,
TUNE_SD18_MASK, TUNE_SD18_3V3);
if (chip->asic_code)
sd_pull_ctl_disable(chip);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20,
FPGA_SD_PULL_CTL_BIT);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0);
if (!chip->option.FT2_fast_mode)
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (!chip->option.FT2_fast_mode) {
#ifdef SD_XD_IO_FOLLOW_PWR
if (CHECK_PKG(chip, LQFP48)
|| chip->option.rts5129_D3318_off_enable)
rts51x_write_register(chip, CARD_PWR_CTL,
LDO_OFF, LDO_OFF);
#endif
wait_timeout(250);
#ifdef SD_XD_IO_FOLLOW_PWR
if (CHECK_PKG(chip, LQFP48)
|| chip->option.rts5129_D3318_off_enable) {
rts51x_init_cmd(chip);
if (chip->asic_code)
sd_pull_ctl_enable(chip);
else
rts51x_add_cmd(chip, WRITE_REG_CMD,
FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20, 0);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
if (chip->asic_code)
rts51x_write_register(chip, CARD_PULL_CTL6,
0x03, 0x00);
}
#endif
/* Power on card */
retval = card_power_on(chip, SD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
wait_timeout(260);
#ifdef SUPPORT_OCP
rts51x_get_card_status(chip, &(chip->card_status));
chip->ocp_stat = (chip->card_status >> 4) & 0x03;
if (chip->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
RTS51X_DEBUGP("Over current, OCPSTAT is 0x%x\n",
chip->ocp_stat);
TRACE_RET(chip, STATUS_FAIL);
}
#endif
}
rts51x_init_cmd(chip);
if (chip->asic_code) {
sd_pull_ctl_enable(chip);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20, 0);
}
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#ifdef SD_XD_IO_FOLLOW_PWR
rts51x_write_register(chip, CARD_INT_PEND, XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
#endif
RTS51X_WRITE_REG(chip, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN);
return STATUS_SUCCESS;
}
static int sd_dummy_clock(struct rts51x_chip *chip)
{
RTS51X_WRITE_REG(chip, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN);
wait_timeout(5);
RTS51X_WRITE_REG(chip, SD_BUS_STAT, SD_CLK_TOGGLE_EN, 0x00);
return STATUS_SUCCESS;
}
int reset_sd(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval, i = 0, j = 0, k = 0, hi_cap_flow = 0;
int sd_dont_switch = 0;
int support_1v8 = 0;
u8 rsp[16];
u8 switch_bus_width;
u32 voltage = 0;
u8 cmd[5], buf[64];
u16 sd_card_type;
SET_SD(sd_card);
CLR_RETRY_SD20_MODE(sd_card);
Switch_Fail:
i = 0;
j = 0;
k = 0;
hi_cap_flow = 0;
support_1v8 = 0;
#ifdef SUPPORT_SD_LOCK
if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
goto SD_UNLOCK_ENTRY;
#endif
retval = sd_prepare_reset(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
sd_dummy_clock(chip);
/* Start Initialization Process of SD Card */
RTY_SD_RST:
retval =
sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL,
0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
wait_timeout(20);
retval =
sd_send_cmd_get_rsp(chip, SEND_IF_COND, 0x000001AA, SD_RSP_TYPE_R7,
rsp, 5);
if (retval == STATUS_SUCCESS) {
if ((rsp[4] == 0xAA) && ((rsp[3] & 0x0f) == 0x01)) {
hi_cap_flow = 1;
if (CHK_RETRY_SD20_MODE(sd_card)) {
voltage =
SUPPORT_VOLTAGE |
SUPPORT_HIGH_AND_EXTENDED_CAPACITY;
} else {
voltage =
SUPPORT_VOLTAGE |
SUPPORT_HIGH_AND_EXTENDED_CAPACITY |
SUPPORT_MAX_POWER_PERMANCE | SUPPORT_1V8;
}
}
}
if (!hi_cap_flow) {
voltage = SUPPORT_VOLTAGE;
retval =
sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
wait_timeout(20);
}
/* ACMD41 */
do {
{
u8 temp = 0;
rts51x_read_register(chip, CARD_INT_PEND, &temp);
RTS51X_DEBUGP("CARD_INT_PEND:%x\n", temp);
if (temp & SD_INT) {
chip->reset_need_retry = 1;
rts51x_write_register(chip, CARD_INT_PEND,
XD_INT | SD_INT | MS_INT,
XD_INT | SD_INT | MS_INT);
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
}
RTY_CMD55:
retval =
sd_send_cmd_get_rsp(chip, APP_CMD, 0, SD_RSP_TYPE_R1, NULL,
0);
if (retval != STATUS_SUCCESS) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, SD_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
j++;
if (chip->option.speed_mmc) {
if (j < 2)
goto RTY_CMD55;
else
TRACE_RET(chip, STATUS_FAIL);
} else {
if (j < 3)
goto RTY_SD_RST;
else
TRACE_RET(chip, STATUS_FAIL);
}
}
retval =
sd_send_cmd_get_rsp(chip, SD_APP_OP_COND, voltage,
SD_RSP_TYPE_R3, rsp, 5);
if (retval != STATUS_SUCCESS) {
k++;
if (k < 3)
goto RTY_SD_RST;
else
TRACE_RET(chip, STATUS_FAIL);
}
i++;
wait_timeout(20);
} while (!(rsp[1] & 0x80) && (i < 255)); /* Not complete power on */
if (i == 255) {
/* Time out */
TRACE_RET(chip, STATUS_FAIL);
}
if (hi_cap_flow) {
if (rsp[1] & 0x40)
SET_SD_HCXC(sd_card);
else
CLR_SD_HCXC(sd_card);
if (!CHK_RETRY_SD20_MODE(sd_card)) {
if ((CHK_SD_HCXC(sd_card)) && (CHECK_UHS50(chip))) {
support_1v8 = (rsp[1] & 0x01) ? 1 : 0;
RTS51X_DEBUGP("support_1v8 = %d\n",
support_1v8);
}
}
} else {
CLR_SD_HCXC(sd_card);
support_1v8 = 0;
}
/* CMD11: Switch Voltage */
if (support_1v8 && CHECK_UHS50(chip)
&& !(((u8) chip->option.sd_speed_prior & SDR104_SUPPORT) ==
HS_SUPPORT)) {
retval = sd_voltage_switch(chip);
if (retval != STATUS_SUCCESS) {
SET_RETRY_SD20_MODE(sd_card);
sd_init_power(chip);
RTS51X_DEBUGP("1.8v switch fail\n");
goto Switch_Fail;
}
}
/* CMD 2 */
retval =
sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* CMD 3 */
retval =
sd_send_cmd_get_rsp(chip, SEND_RELATIVE_ADDR, 0, SD_RSP_TYPE_R6,
rsp, 5);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
sd_card->sd_addr = (u32) rsp[1] << 24;
sd_card->sd_addr += (u32) rsp[2] << 16;
/* Get CSD register for Calculating Timing,Capacity,
* Check CSD to determaine as if this is the SD ROM card */
retval = sd_check_csd(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Select SD card */
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#ifdef SUPPORT_SD_LOCK
SD_UNLOCK_ENTRY:
/* Get SD lock status */
retval = sd_update_lock_status(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
if (sd_card->sd_lock_status & SD_LOCKED) {
sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST);
return STATUS_SUCCESS;
} else if (!(sd_card->sd_lock_status & SD_UNLOCK_POW_ON)) {
sd_card->sd_lock_status &= ~SD_PWD_EXIST;
}
#endif
/* ACMD42 */
retval =
sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval =
sd_send_cmd_get_rsp(chip, SET_CLR_CARD_DETECT, 0, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (support_1v8) {
/* ACMD6 */
retval =
sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Enable 4 bit data bus */
retval =
sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
switch_bus_width = SD_BUS_WIDTH_4;
} else {
switch_bus_width = SD_BUS_WIDTH_1;
}
/* Set block length 512 bytes for all block commands */
retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN,
0x200, SD_RSP_TYPE_R1, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_WRITE_REG(chip, SD_CFG1, SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
if (!(sd_card->raw_csd[4] & 0x40)) {
sd_dont_switch = 1;
RTS51X_DEBUGP("Not support class ten\n");
}
if (!sd_dont_switch) {
/* Check the card whether flow SD1.1 spec or higher */
retval = sd_check_spec(chip, switch_bus_width);
if (retval == STATUS_SUCCESS) {
retval = sd_switch_function(chip, switch_bus_width);
if (retval != STATUS_SUCCESS) {
if ((sd_card->sd_switch_fail ==
SDR104_SUPPORT_MASK)
|| (sd_card->sd_switch_fail ==
DDR50_SUPPORT_MASK)
|| (sd_card->sd_switch_fail ==
SDR50_SUPPORT_MASK)) {
sd_init_power(chip);
SET_RETRY_SD20_MODE(sd_card);
} else if (sd_card->sd_switch_fail ==
HS_SUPPORT_MASK) {
sd_dont_switch = 1;
}
goto Switch_Fail;
}
} else {
if (support_1v8) {
SET_RETRY_SD20_MODE(sd_card);
sd_init_power(chip);
sd_dont_switch = 1;
goto Switch_Fail;
}
}
}
if (!support_1v8) {
/* ACMD6 */
retval =
sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Enable 4 bit data bus */
retval =
sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
#ifdef SUPPORT_SD_LOCK
/* clear 1 bit mode status */
sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
#endif
if (CHK_SD30_SPEED(sd_card)) {
rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK,
0x03);
retval = sd_set_init_para(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (CHK_SD_DDR50(sd_card))
retval = sd_ddr_tuning(chip);
else
retval = sd_sdr_tuning(chip);
if (retval != STATUS_SUCCESS) {
SET_RETRY_SD20_MODE(sd_card);
RTS51X_DEBUGP("tuning phase fail,goto SD20 mode\n");
sd_init_power(chip);
CLR_SD30_SPEED(sd_card);
goto Switch_Fail;
}
if (STATUS_SUCCESS ==
sd_wait_currentstate_dataready(chip, 0x08, 1, 20)) {
cmd[0] = 0x40 | READ_SINGLE_BLOCK;
cmd[1] = 0x00;
cmd[2] = 0x00;
cmd[3] = 0x00;
cmd[4] = 0x00;
retval =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 512,
1, SD_BUS_WIDTH_4, NULL, 0, 600);
if (retval != STATUS_SUCCESS) {
SET_RETRY_SD20_MODE(sd_card);
RTS51X_DEBUGP("read lba0 fail,"
"goto SD20 mode\n");
sd_init_power(chip);
CLR_SD30_SPEED(sd_card);
goto Switch_Fail;
}
}
}
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
if (retval == STATUS_SUCCESS) {
int ret;
cmd[0] = 0x40 | SEND_STATUS;
cmd[1] = 0x00;
cmd[2] = 0x00;
cmd[3] = 0x00;
cmd[4] = 0x00;
ret =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, 64, 1,
SD_BUS_WIDTH_4, buf, 64, 600);
if (ret == STATUS_SUCCESS) {
sd_card_type = ((u16) buf[2] << 8) | (u16) buf[3];
RTS51X_DEBUGP("sd_card_type:0x%4x\n", sd_card_type);
if ((sd_card_type == 0x0001)
|| (sd_card_type == 0x0002))
chip->card_wp |= SD_CARD;
} else {
rts51x_clear_sd_error(chip);
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
}
} else {
rts51x_clear_sd_error(chip);
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
}
/* Check SD Machanical Write-Protect Switch */
retval = rts51x_get_card_status(chip, &(chip->card_status));
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (chip->card_status & SD_WP)
chip->card_wp |= SD_CARD;
chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
#ifdef SUPPORT_SD_LOCK
if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
#endif
return STATUS_SUCCESS;
}
static int mmc_test_switch_bus(struct rts51x_chip *chip, u8 width)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 buf[8] = { 0 }, bus_width;
u16 byte_cnt;
int len;
retval =
sd_send_cmd_get_rsp(chip, BUSTEST_W, 0, SD_RSP_TYPE_R1, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (width == MMC_8BIT_BUS) {
buf[0] = 0x55;
buf[1] = 0xAA;
len = 8;
byte_cnt = 8;
bus_width = SD_BUS_WIDTH_8;
} else {
buf[0] = 0x5A;
len = 4;
byte_cnt = 4;
bus_width = SD_BUS_WIDTH_4;
}
retval = sd_write_data(chip, SD_TM_AUTO_WRITE_3,
NULL, 0, byte_cnt, 1, bus_width, buf, len, 100);
if (retval != STATUS_SUCCESS) {
u8 val1 = 0, val2 = 0;
rts51x_ep0_read_register(chip, SD_STAT1, &val1);
rts51x_ep0_read_register(chip, SD_STAT2, &val2);
rts51x_clear_sd_error(chip);
if ((val1 & 0xE0) || val2)
TRACE_RET(chip, STATUS_FAIL);
}
RTS51X_DEBUGP("SD/MMC CMD %d\n", BUSTEST_R);
rts51x_init_cmd(chip);
/* CMD14 */
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | BUSTEST_R);
if (width == MMC_8BIT_BUS)
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x08);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x04);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_NO_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_NORMAL_READ | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END,
SD_TRANSFER_END);
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2, 0, 0);
if (width == MMC_8BIT_BUS) {
len = 3;
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 1, 0, 0);
} else {
len = 2;
}
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, len, 100);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
rts51x_read_rsp_buf(chip, 1, buf, 2);
if (width == MMC_8BIT_BUS) {
RTS51X_DEBUGP("BUSTEST_R [8bits]: 0x%02x 0x%02x\n",
buf[0], buf[1]);
if ((buf[0] == 0xAA) && (buf[1] == 0x55)) {
u8 rsp[5];
u32 arg;
if (CHK_MMC_DDR52(sd_card))
arg = 0x03B70600;
else
arg = 0x03B70200;
/* Switch MMC to 8-bit mode */
retval =
sd_send_cmd_get_rsp(chip, SWITCH, arg,
SD_RSP_TYPE_R1b, rsp, 5);
if ((retval == STATUS_SUCCESS)
&& !(rsp[4] & MMC_SWITCH_ERR))
return STATUS_SUCCESS;
}
} else {
RTS51X_DEBUGP("BUSTEST_R [4bits]: 0x%02x\n", buf[0]);
if (buf[0] == 0xA5) {
u8 rsp[5];
u32 arg;
if (CHK_MMC_DDR52(sd_card))
arg = 0x03B70500;
else
arg = 0x03B70100;
/* Switch MMC to 4-bit mode */
retval =
sd_send_cmd_get_rsp(chip, SWITCH, arg,
SD_RSP_TYPE_R1b, rsp, 5);
if ((retval == STATUS_SUCCESS)
&& !(rsp[4] & MMC_SWITCH_ERR))
return STATUS_SUCCESS;
}
}
TRACE_RET(chip, STATUS_FAIL);
}
static int mmc_switch_timing_bus(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
u8 card_type, card_type_mask = 0;
u8 buf[6];
CLR_MMC_HS(sd_card);
RTS51X_DEBUGP("SD/MMC CMD %d\n", SEND_EXT_CSD);
rts51x_init_cmd(chip);
/* SEND_EXT_CSD command */
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF,
0x40 | SEND_EXT_CSD);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 2);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END
| SD_CHECK_CRC7 | SD_RSP_LEN_6);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_NORMAL_READ | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END,
SD_TRANSFER_END);
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 196, 0xFF, 0);
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 212, 0xFF, 0);
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 213, 0xFF, 0);
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 214, 0xFF, 0);
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 215, 0xFF, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 6, 1000);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
if (retval == STATUS_TIMEDOUT) {
rts51x_clear_sd_error(chip);
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
}
TRACE_RET(chip, STATUS_FAIL);
}
rts51x_read_rsp_buf(chip, 0, buf, 6);
if (buf[0] & SD_TRANSFER_ERR) {
sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
TRACE_RET(chip, STATUS_FAIL);
}
if (CHK_MMC_SECTOR_MODE(sd_card))
sd_card->capacity =
((u32) buf[5] << 24) | ((u32) buf[4] << 16) |
((u32) buf[3] << 8) | ((u32) buf[2]);
#ifdef SUPPORT_SD_LOCK
if (!(sd_card->sd_lock_status & SD_SDR_RST) && CHECK_UHS50(chip))
card_type_mask = 0x07;
else
card_type_mask = 0x03;
#else
if (CHECK_UHS50(chip))
card_type_mask = 0x07;
else
card_type_mask = 0x03;
#endif
card_type = buf[1] & card_type_mask;
if (card_type) {
/* CARD TYPE FIELD = DDR52MHz, 52MHz or 26MHz */
u8 rsp[5];
if (card_type & 0x04)
SET_MMC_DDR52(sd_card);
else if (card_type & 0x02)
SET_MMC_52M(sd_card);
else
SET_MMC_26M(sd_card);
retval =
sd_send_cmd_get_rsp(chip, SWITCH, 0x03B90100,
SD_RSP_TYPE_R1b, rsp, 5);
if ((retval != STATUS_SUCCESS) || (rsp[4] & MMC_SWITCH_ERR))
CLR_MMC_HS(sd_card);
}
sd_choose_proper_clock(chip);
retval = switch_clock(chip, sd_card->sd_clock);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Test Bus Procedure */
if (mmc_test_switch_bus(chip, MMC_8BIT_BUS) == STATUS_SUCCESS) {
SET_MMC_8BIT(sd_card);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 8;
#ifdef SUPPORT_SD_LOCK
sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
#endif
} else if (mmc_test_switch_bus(chip, MMC_4BIT_BUS) == STATUS_SUCCESS) {
SET_MMC_4BIT(sd_card);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
#ifdef SUPPORT_SD_LOCK
sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
#endif
} else {
CLR_MMC_8BIT(sd_card);
CLR_MMC_4BIT(sd_card);
}
return STATUS_SUCCESS;
}
static int reset_mmc(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval, i = 0, j = 0, k = 0;
u8 rsp[16];
u8 spec_ver = 0;
u8 change_to_ddr52 = 1;
u8 cmd[5];
#ifdef SUPPORT_SD_LOCK
if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
goto MMC_UNLOCK_ENTRY;
#endif
MMC_DDR_FAIL:
retval = sd_prepare_reset(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
SET_MMC(sd_card);
RTY_MMC_RST:
retval =
sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL,
0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
do {
{
u8 temp = 0;
rts51x_read_register(chip, CARD_INT_PEND, &temp);
if (temp & SD_INT) {
chip->reset_need_retry = 1;
rts51x_write_register(chip, CARD_INT_PEND,
XD_INT | SD_INT | MS_INT,
XD_INT | SD_INT | MS_INT);
sd_set_reset_fail(chip, MMC_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
}
/* CMD 1 */
retval = sd_send_cmd_get_rsp(chip, SEND_OP_COND,
(SUPPORT_VOLTAGE | 0x40000000),
SD_RSP_TYPE_R3, rsp, 5);
if (retval != STATUS_SUCCESS) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
sd_set_reset_fail(chip, MMC_RESET_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
if (sd_check_err_code(chip, SD_BUSY)
|| sd_check_err_code(chip, SD_TO_ERR)) {
k++;
if (k < 20) {
sd_clr_err_code(chip);
goto RTY_MMC_RST;
} else {
TRACE_RET(chip, STATUS_FAIL);
}
} else {
j++;
if (j < 100) {
sd_clr_err_code(chip);
goto RTY_MMC_RST;
} else {
TRACE_RET(chip, STATUS_FAIL);
}
}
}
wait_timeout(20);
i++;
} while (!(rsp[1] & 0x80) && (i < 100)); /* Not complete power on */
if (i == 100) {
/* Time out */
TRACE_RET(chip, STATUS_FAIL);
}
if ((rsp[1] & 0x60) == 0x40)
SET_MMC_SECTOR_MODE(sd_card);
else
CLR_MMC_SECTOR_MODE(sd_card);
/* CMD 2 */
retval =
sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* CMD 3 */
sd_card->sd_addr = 0x00100000;
retval =
sd_send_cmd_get_rsp(chip, SET_RELATIVE_ADDR, sd_card->sd_addr,
SD_RSP_TYPE_R6, rsp, 5);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Get CSD register for Calculating Timing,Capacity
* Check CSD to determaine as if this is the SD ROM card */
retval = sd_check_csd(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Get MMC Spec_Ver in the CSD register */
spec_ver = (sd_card->raw_csd[0] & 0x3C) >> 2;
/* Select MMC card */
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
/* Set block length 512 bytes for all block commands */
retval =
sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL,
0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#ifdef SUPPORT_SD_LOCK
MMC_UNLOCK_ENTRY:
/* Get SD lock status */
retval = sd_update_lock_status(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
#endif
RTS51X_WRITE_REG(chip, SD_CFG1, SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
if (chip->ic_version < 2)
rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK,
0x02);
rts51x_write_register(chip, CARD_DRIVE_SEL, SD20_DRIVE_MASK, DRIVE_8mA);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 1;
if (spec_ver == 4) {
/* MMC 4.x Cards */
(void)mmc_switch_timing_bus(chip);
}
if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0))
TRACE_RET(chip, STATUS_FAIL);
if (CHK_MMC_DDR52(sd_card) && change_to_ddr52) {
/* Card is extracted while identifying */
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST)
TRACE_RET(chip, STATUS_FAIL);
retval = sd_set_init_para(chip);
if (retval != STATUS_SUCCESS) {
CLR_MMC_DDR52(sd_card);
sd_init_power(chip);
change_to_ddr52 = 0;
goto MMC_DDR_FAIL;
}
retval = mmc_ddr_tuning(chip);
if (retval != STATUS_SUCCESS) {
CLR_MMC_DDR52(sd_card);
sd_init_power(chip);
change_to_ddr52 = 0;
goto MMC_DDR_FAIL;
}
if (STATUS_SUCCESS ==
sd_wait_currentstate_dataready(chip, 0x08, 1, 20)) {
cmd[0] = 0x40 | READ_SINGLE_BLOCK;
cmd[1] = 0x00;
cmd[2] = 0x00;
cmd[3] = 0x00;
cmd[4] = 0x00;
if (CHK_MMC_8BIT(sd_card)) {
retval =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd,
5, 512, 1, SD_BUS_WIDTH_8,
NULL, 0, 600);
} else if (CHK_MMC_4BIT(sd_card)) {
retval =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd,
5, 512, 1, SD_BUS_WIDTH_4,
NULL, 0, 600);
} else {
retval =
sd_read_data(chip, SD_TM_NORMAL_READ, cmd,
5, 512, 1, SD_BUS_WIDTH_1,
NULL, 0, 600);
}
if (retval != STATUS_SUCCESS) {
CLR_MMC_DDR52(sd_card);
change_to_ddr52 = 0;
RTS51X_DEBUGP("read lba0 fail,"
"goto SD20 mode\n");
sd_init_power(chip);
goto MMC_DDR_FAIL;
}
}
}
#ifdef SUPPORT_SD_LOCK
if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
#endif
retval = rts51x_get_card_status(chip, &(chip->card_status));
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (chip->card_status & SD_WP)
chip->card_wp |= SD_CARD;
return STATUS_SUCCESS;
}
int reset_sd_card(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
int i;
memset(sd_card, 0, sizeof(struct sd_info));
/* Init variables */
sd_card->sd_type = 0;
sd_card->seq_mode = 0;
sd_card->sd_data_buf_ready = 0;
sd_card->capacity = 0;
sd_card->sd_switch_fail = 0;
#ifdef SUPPORT_SD_LOCK
sd_card->sd_lock_status = 0;
sd_card->sd_erase_status = 0;
#endif
sd_clear_reset_fail(chip);
enable_card_clock(chip, SD_CARD);
sd_init_power(chip);
chip->reset_need_retry = 0;
for (i = 0; i < 3; i++) {
if (!chip->option.reset_mmc_first) { /* reset sd first */
retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
/* Switch SD bus to 3V3 signal */
RTS51X_WRITE_REG(chip, SD_PAD_CTL,
SD_IO_USING_1V8, 0);
if (sd_check_reset_fail(chip, SD_RESET_FAIL))
sd_clear_reset_fail(chip);
else
retval = reset_mmc(chip);
}
} else { /* reset MMC first */
retval = reset_mmc(chip);
if (retval != STATUS_SUCCESS) {
if (sd_check_reset_fail(chip, MMC_RESET_FAIL)) {
sd_clear_reset_fail(chip);
} else {
retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
/* Switch SD bus to
* 3V3 signal */
RTS51X_WRITE_REG(chip,
SD_PAD_CTL,
SD_IO_USING_1V8, 0);
}
}
}
}
if ((retval == STATUS_SUCCESS) || (!chip->reset_need_retry)) {
/* if reset success or don't need retry,then break */
break;
}
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST) {
/* card is extracted */
break;
}
RTS51X_DEBUGP("retry reset sd card,%d\n", i);
chip->reset_need_retry = 0;
}
sd_clear_reset_fail(chip);
chip->reset_need_retry = 0;
if (retval == STATUS_SUCCESS) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, SD_CLK_DIVIDE_MASK,
SD_CLK_DIVIDE_0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 2);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity = 0;
if (chip->option.reset_or_rw_fail_set_pad_drive) {
rts51x_write_register(chip, CARD_DRIVE_SEL,
SD20_DRIVE_MASK, DRIVE_8mA);
}
TRACE_RET(chip, STATUS_FAIL);
}
chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity;
if (chip->option.sd_send_status_en) {
sd_card->sd_send_status_en = 1;
} else {
if (sd_card->capacity > 0x20000) { /* 64MB */
sd_card->sd_send_status_en = 0;
} else {
sd_card->sd_send_status_en = 1;
}
}
RTS51X_DEBUGP("sd_card->sd_send_status = %d\n",
sd_card->sd_send_status_en);
retval = sd_set_init_para(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_DEBUGP("sd_card->sd_type = 0x%x\n", sd_card->sd_type);
return STATUS_SUCCESS;
}
#define WAIT_DATA_READY_RTY_CNT 255
static int wait_data_buf_ready(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int i, retval;
for (i = 0; i < WAIT_DATA_READY_RTY_CNT; i++) {
if (monitor_card_cd(chip, SD_CARD) == CD_NOT_EXIST)
TRACE_RET(chip, STATUS_FAIL);
sd_card->sd_data_buf_ready = 0;
retval = sd_send_cmd_get_rsp(chip, SEND_STATUS,
sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (sd_card->sd_data_buf_ready)
return sd_send_cmd_get_rsp(chip, SEND_STATUS,
sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0);
}
sd_set_err_code(chip, SD_TO_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
void sd_stop_seq_mode(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
if (sd_card->seq_mode) {
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
return;
retval = sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0,
SD_RSP_TYPE_R1b, NULL, 0);
if (retval != STATUS_SUCCESS)
sd_set_err_code(chip, SD_STS_ERR);
sd_card->seq_mode = 0;
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH,
FIFO_FLUSH);
}
}
static inline int sd_auto_tune_clock(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
if (chip->asic_code) {
if (sd_card->sd_clock > 30)
sd_card->sd_clock -= 20;
} else {
if (sd_card->sd_clock == CLK_100)
sd_card->sd_clock = CLK_80;
else if (sd_card->sd_clock == CLK_80)
sd_card->sd_clock = CLK_60;
else if (sd_card->sd_clock == CLK_60)
sd_card->sd_clock = CLK_50;
}
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int sd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt)
{
struct sd_info *sd_card = &(chip->sd_card);
u32 data_addr;
int retval;
u8 flag;
unsigned int pipe;
u8 stageflag;
sd_card->counter = 0;
if (!CHK_SD_HCXC(sd_card) && !CHK_MMC_SECTOR_MODE(sd_card))
data_addr = start_sector << 9;
else
data_addr = start_sector;
RTS51X_DEBUGP("sd_rw, data_addr = 0x%x\n", data_addr);
sd_clr_err_code(chip);
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (sd_card->seq_mode && ((sd_card->pre_dir != srb->sc_data_direction)
||
((sd_card->pre_sec_addr +
sd_card->pre_sec_cnt) != start_sector))) {
if ((sd_card->pre_dir == DMA_FROM_DEVICE)
&& !CHK_SD30_SPEED(sd_card)
&& !CHK_SD_HS(sd_card)
&& !CHK_MMC_HS(sd_card)
&& sd_card->sd_send_status_en) {
sd_send_cmd_get_rsp(chip, SEND_STATUS,
sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
}
retval =
sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0,
SD_RSP_TYPE_R1b, NULL, 0);
if (retval != STATUS_SUCCESS) {
sd_set_err_code(chip, SD_STS_ERR);
TRACE_RET(chip, sd_parse_err_code(chip));
}
sd_card->seq_mode = 0;
RTS51X_WRITE_REG(chip, MC_FIFO_CTL, FIFO_FLUSH, FIFO_FLUSH);
if (!CHK_SD30_SPEED(sd_card)
&& !CHK_SD_HS(sd_card)
&& !CHK_MMC_HS(sd_card)
&& sd_card->sd_send_status_en) {
/* random rw, so pre_sec_cnt < 0x80 */
sd_send_cmd_get_rsp(chip, SEND_STATUS,
sd_card->sd_addr, SD_RSP_TYPE_R1,
NULL, 0);
}
}
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF,
(u8) sector_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF,
(u8) (sector_cnt >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
RING_BUFFER);
if (CHK_MMC_8BIT(sd_card))
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03,
SD_BUS_WIDTH_8);
else if (CHK_MMC_4BIT(sd_card) || CHK_SD(sd_card))
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03,
SD_BUS_WIDTH_4);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03,
SD_BUS_WIDTH_1);
if (sd_card->seq_mode) {
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 |
SD_RSP_LEN_0);
trans_dma_enable(srb->sc_data_direction, chip, sector_cnt * 512,
DMA_512);
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
flag = MODE_CDIR;
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_READ_3 | SD_TRANSFER_START);
} else {
flag = MODE_CDOR;
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START);
}
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, flag, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
RTS51X_DEBUGP("SD/MMC CMD %d\n", READ_MULTIPLE_BLOCK);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF,
0x40 | READ_MULTIPLE_BLOCK);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF,
(u8) (data_addr >> 24));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF,
(u8) (data_addr >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF,
(u8) (data_addr >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF,
(u8) data_addr);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 |
SD_RSP_LEN_6);
trans_dma_enable(srb->sc_data_direction, chip,
sector_cnt * 512, DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_READ_2 | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CDIR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
} else {
retval = rts51x_send_cmd(chip, MODE_C, 50);
if (retval != STATUS_SUCCESS) {
rts51x_clear_sd_error(chip);
sd_set_err_code(chip, SD_TO_ERR);
TRACE_RET(chip, sd_parse_err_code(chip));
}
retval = wait_data_buf_ready(chip);
if (retval != STATUS_SUCCESS) {
sd_set_err_code(chip, SD_TO_ERR);
TRACE_RET(chip, sd_parse_err_code(chip));
}
retval = sd_send_cmd_get_rsp(chip, WRITE_MULTIPLE_BLOCK,
data_addr, SD_RSP_TYPE_R1,
NULL, 0);
if (retval != STATUS_SUCCESS) {
sd_set_err_code(chip, SD_CRC_ERR);
TRACE_RET(chip, sd_parse_err_code(chip));
}
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF,
SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 |
SD_RSP_LEN_0);
trans_dma_enable(srb->sc_data_direction, chip,
sector_cnt * 512, DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CDOR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
sd_card->seq_mode = 1;
}
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
pipe = RCV_BULK_PIPE(chip);
stageflag = STAGE_DI;
} else {
pipe = SND_BULK_PIPE(chip);
stageflag = STAGE_DO;
}
retval =
rts51x_transfer_data_rcc(chip, pipe, scsi_sglist(srb),
scsi_bufflen(srb), scsi_sg_count(srb),
NULL, 10000, stageflag);
if (retval != STATUS_SUCCESS) {
u8 stat = 0;
int err = retval;
sd_print_debug_reg(chip);
rts51x_ep0_read_register(chip, SD_STAT1, &stat);
RTS51X_DEBUGP("SD_STAT1: 0x%x\n", stat);
rts51x_clear_sd_error(chip);
retval =
sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0,
SD_RSP_TYPE_R1b, NULL, 0);
if (retval != STATUS_SUCCESS) {
sd_set_err_code(chip, SD_STS_ERR);
TRACE_RET(chip, retval);
}
if (stat & (SD_CRC7_ERR | SD_CRC16_ERR | SD_CRC_WRITE_ERR)) {
RTS51X_DEBUGP("SD CRC error, tune clock!\n");
sd_auto_tune_clock(chip);
}
sd_card->seq_mode = 0;
TRACE_RET(chip, err);
}
retval = rts51x_get_rsp(chip, 1, 2000);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
rts51x_clear_sd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
sd_card->pre_sec_addr = start_sector;
sd_card->pre_sec_cnt = sector_cnt;
sd_card->pre_dir = srb->sc_data_direction;
return STATUS_SUCCESS;
}
void sd_cleanup_work(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
if (sd_card->seq_mode) {
RTS51X_DEBUGP("SD: stop transmission\n");
sd_stop_seq_mode(chip);
sd_card->counter = 0;
}
}
inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
{
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0);
if (!chip->option.FT2_fast_mode) {
#ifdef SD_XD_IO_FOLLOW_PWR
if (CHECK_PKG(chip, LQFP48)
|| chip->option.rts5129_D3318_off_enable)
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL,
POWER_MASK | LDO_OFF,
POWER_OFF | LDO_OFF);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL,
POWER_MASK, POWER_OFF);
#else
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
#endif
}
}
int sd_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
rts51x_init_cmd(chip);
sd_fill_power_off_card3v3(chip);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#ifdef SD_XD_IO_FOLLOW_PWR
if (!chip->option.FT2_fast_mode)
wait_timeout(chip->option.D3318_off_delay);
#endif
return STATUS_SUCCESS;
}
int release_sd_card(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
RTS51X_DEBUGP("elease_sd_card\n");
chip->card_ready &= ~SD_CARD;
chip->card_fail &= ~SD_CARD;
chip->card_wp &= ~SD_CARD;
#ifdef SUPPORT_SD_LOCK
sd_card->sd_lock_status = 0;
sd_card->sd_erase_status = 0;
#endif
memset(sd_card->raw_csd, 0, 16);
memset(sd_card->raw_scr, 0, 8);
rts51x_write_register(chip, SFSM_ED, HW_CMD_STOP, HW_CMD_STOP);
rts51x_write_register(chip, SD_PAD_CTL, SD_IO_USING_1V8, 0);
if (CHECK_PKG(chip, LQFP48) || chip->option.rts5129_D3318_off_enable)
sd_power_off_card3v3(chip);
rts51x_init_cmd(chip);
if (!(CHECK_PKG(chip, LQFP48) || chip->option.rts5129_D3318_off_enable))
sd_fill_power_off_card3v3(chip);
if (chip->asic_code)
sd_pull_ctl_disable(chip);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL,
FPGA_SD_PULL_CTL_BIT | 0x20,
FPGA_SD_PULL_CTL_BIT);
/* Switch LDO3318 to 3.3V */
rts51x_add_cmd(chip, WRITE_REG_CMD, LDO_POWER_CFG, TUNE_SD18_MASK,
TUNE_SD18_3V3);
if (CHK_MMC_DDR52(sd_card) && CHK_MMC_8BIT(sd_card))
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
EXTEND_DMA1_ASYNC_SIGNAL,
EXTEND_DMA1_ASYNC_SIGNAL);
if (CHK_SD30_SPEED(sd_card) || CHK_MMC(sd_card))
rts51x_add_cmd(chip, WRITE_REG_CMD, SD30_DRIVE_SEL,
SD30_DRIVE_MASK, chip->option.sd30_pad_drive);
/* Suspend LDO3318 */
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, LDO3318_PWR_MASK,
LDO_SUSPEND);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
wait_timeout(20);
return STATUS_SUCCESS;
}
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_SD_H
#define __RTS51X_SD_H
#include "rts51x_chip.h"
#define SD_MAX_RETRY_COUNT 3
#define SUPPORT_VOLTAGE 0x003C0000
#define SD_RESET_FAIL 0x01
#define MMC_RESET_FAIL 0x02
/* Error Code */
#define SD_NO_ERROR 0x0
#define SD_CRC_ERR 0x80
#define SD_TO_ERR 0x40
#define SD_NO_CARD 0x20
#define SD_BUSY 0x10
#define SD_STS_ERR 0x08
#define SD_RSP_TIMEOUT 0x04
/* MMC/SD Command Index */
/* Basic command (class 0) */
#define GO_IDLE_STATE 0
#define SEND_OP_COND 1 /* reserved for SD */
#define ALL_SEND_CID 2
#define SET_RELATIVE_ADDR 3
#define SEND_RELATIVE_ADDR 3
#define SET_DSR 4
#define IO_SEND_OP_COND 5
#define SWITCH 6
#define SELECT_CARD 7
#define DESELECT_CARD 7
/* CMD8 is "SEND_EXT_CSD" for MMC4.x Spec
* while is "SEND_IF_COND" for SD 2.0 */
#define SEND_EXT_CSD 8
#define SEND_IF_COND 8
/* end */
#define SEND_CSD 9
#define SEND_CID 10
#define VOLTAGE_SWITCH 11
#define READ_DAT_UTIL_STOP 11 /* reserved for SD */
#define STOP_TRANSMISSION 12
#define SEND_STATUS 13
#define GO_INACTIVE_STATE 15
/* Block oriented read commands (class 2) */
#define SET_BLOCKLEN 16
#define READ_SINGLE_BLOCK 17
#define READ_MULTIPLE_BLOCK 18
#define SEND_TUNING_PATTERN 19
/* Bus Width Test */
#define BUSTEST_R 14
#define BUSTEST_W 19
/* end */
/* Block oriented write commands (class 4) */
#define WRITE_BLOCK 24
#define WRITE_MULTIPLE_BLOCK 25
#define PROGRAM_CSD 27
/* Erase commands */
#define ERASE_WR_BLK_START 32
#define ERASE_WR_BLK_END 33
#define ERASE_CMD 38
/* Block Oriented Write Protection Commands */
#define LOCK_UNLOCK 42
#define IO_RW_DIRECT 52
/* Application specific commands (class 8) */
#define APP_CMD 55
#define GEN_CMD 56
/* SD Application command Index */
#define SET_BUS_WIDTH 6
#define SD_STATUS 13
#define SEND_NUM_WR_BLOCKS 22
#define SET_WR_BLK_ERASE_COUNT 23
#define SD_APP_OP_COND 41
#define SET_CLR_CARD_DETECT 42
#define SEND_SCR 51
/* SD TIMEOUT function return error */
#define SD_READ_COMPLETE 0x00
#define SD_READ_TO 0x01
#define SD_READ_ADVENCE 0x02
/* SD v1.1 CMD6 SWITCH function */
#define SD_CHECK_MODE 0x00
#define SD_SWITCH_MODE 0x80
#define SD_FUNC_GROUP_1 0x01
#define SD_FUNC_GROUP_2 0x02
#define SD_FUNC_GROUP_3 0x03
#define SD_FUNC_GROUP_4 0x04
#define SD_CHECK_SPEC_V1_1 0xFF
/* SD Command Argument */
#define NO_ARGUMENT 0x00
#define CHECK_PATTERN 0x000000AA
#define VOLTAGE_SUPPLY_RANGE 0x00000100 /* 2.7~3.6V */
#define SUPPORT_HIGH_AND_EXTENDED_CAPACITY 0x40000000
#define SUPPORT_MAX_POWER_PERMANCE 0x10000000
#define SUPPORT_1V8 0x01000000
/* Switch Command Error Code */
#define SWTICH_NO_ERR 0x00
#define CARD_NOT_EXIST 0x01
#define SPEC_NOT_SUPPORT 0x02
#define CHECK_MODE_ERR 0x03
#define CHECK_NOT_READY 0x04
#define SWITCH_CRC_ERR 0x05
#define SWITCH_MODE_ERR 0x06
#define SWITCH_PASS 0x07
#ifdef SUPPORT_SD_LOCK
/* CMD42 Parameter */
#define SD_ERASE 0x08
#define SD_LOCK 0x04
#define SD_UNLOCK 0x00
#define SD_CLR_PWD 0x02
#define SD_SET_PWD 0x01
#define SD_PWD_LEN 0x10
/* SD lock unlock Status */
#define SD_LOCKED 0x80 /* Global lock status */
#define SD_LOCK_1BIT_MODE 0x40 /**/
#define SD_PWD_EXIST 0x20
#define SD_UNLOCK_POW_ON 0x01 /**/
#define SD_SDR_RST 0x02 /* Reset SD30 card with current DDR mode to SDR mode. */
/* g_bySDEraseStatus */
#define SD_NOT_ERASE 0x00
#define SD_UNDER_ERASING 0x01
#define SD_COMPLETE_ERASE 0x02
/* SD_RW FAIL status */
#define SD_RW_FORBIDDEN 0x0F /* read/write is forbidden (SD card) */
#endif
/* Function Group Definition */
/* Function Group 1 */
#define HS_SUPPORT 0x01
#define SDR50_SUPPORT 0x02
#define SDR104_SUPPORT 0x03
#define DDR50_SUPPORT 0x04
#define HS_SUPPORT_MASK 0x02
#define SDR50_SUPPORT_MASK 0x04
#define SDR104_SUPPORT_MASK 0x08
#define DDR50_SUPPORT_MASK 0x10
#define HS_QUERY_SWITCH_OK 0x01
#define SDR50_QUERY_SWITCH_OK 0x02
#define SDR104_QUERY_SWITCH_OK 0x03
#define DDR50_QUERY_SWITCH_OK 0x04
#define HS_SWITCH_BUSY 0x02
#define SDR50_SWITCH_BUSY 0x04
#define SDR104_SWITCH_BUSY 0x08
#define DDR50_SWITCH_BUSY 0x10
#define FUNCTION_GROUP1_SUPPORT_OFFSET 0x0D
#define FUNCTION_GROUP1_QUERY_SWITCH_OFFSET 0x10
#define FUNCTION_GROUP1_CHECK_BUSY_OFFSET 0x1D
/* Function Group 3 */
#define DRIVING_TYPE_A 0x01
#define DRIVING_TYPE_B 0x00
#define DRIVING_TYPE_C 0x02
#define DRIVING_TYPE_D 0x03
#define DRIVING_TYPE_A_MASK 0x02
#define DRIVING_TYPE_B_MASK 0x01
#define DRIVING_TYPE_C_MASK 0x04
#define DRIVING_TYPE_D_MASK 0x08
#define TYPE_A_QUERY_SWITCH_OK 0x01
#define TYPE_B_QUERY_SWITCH_OK 0x00
#define TYPE_C_QUERY_SWITCH_OK 0x02
#define TYPE_D_QUERY_SWITCH_OK 0x03
#define TYPE_A_SWITCH_BUSY 0x02
#define TYPE_B_SWITCH_BUSY 0x01
#define TYPE_C_SWITCH_BUSY 0x04
#define TYPE_D_SWITCH_BUSY 0x08
#define FUNCTION_GROUP3_SUPPORT_OFFSET 0x09
#define FUNCTION_GROUP3_QUERY_SWITCH_OFFSET 0x0F
#define FUNCTION_GROUP3_CHECK_BUSY_OFFSET 0x19
/* Function Group 4 */
#define CURRENT_LIMIT_200 0x00
#define CURRENT_LIMIT_400 0x01
#define CURRENT_LIMIT_600 0x02
#define CURRENT_LIMIT_800 0x03
#define CURRENT_LIMIT_200_MASK 0x01
#define CURRENT_LIMIT_400_MASK 0x02
#define CURRENT_LIMIT_600_MASK 0x04
#define CURRENT_LIMIT_800_MASK 0x08
#define CURRENT_LIMIT_200_QUERY_SWITCH_OK 0x00
#define CURRENT_LIMIT_400_QUERY_SWITCH_OK 0x01
#define CURRENT_LIMIT_600_QUERY_SWITCH_OK 0x02
#define CURRENT_LIMIT_800_QUERY_SWITCH_OK 0x03
#define CURRENT_LIMIT_200_SWITCH_BUSY 0x01
#define CURRENT_LIMIT_400_SWITCH_BUSY 0x02
#define CURRENT_LIMIT_600_SWITCH_BUSY 0x04
#define CURRENT_LIMIT_800_SWITCH_BUSY 0x08
#define FUNCTION_GROUP4_SUPPORT_OFFSET 0x07
#define FUNCTION_GROUP4_QUERY_SWITCH_OFFSET 0x0F
#define FUNCTION_GROUP4_CHECK_BUSY_OFFSET 0x17
/* Switch Function Status Offset */
#define DATA_STRUCTURE_VER_OFFSET 0x11 /* The high offset */
#define MAX_PHASE 15
/* #define TOTAL_READ_PHASE 0x20 */
/* #define TOTAL_WRITE_PHASE 0x20 */
/* MMC v4.0 */
/* #define MMC_52MHZ_SPEED 0x0001 */
/* #define MMC_26MHZ_SPEED 0x0002 */
#define MMC_8BIT_BUS 0x0010
#define MMC_4BIT_BUS 0x0020
/* #define MMC_SECTOR_MODE 0x0100 */
#define MMC_SWITCH_ERR 0x80
/* Tuning direction RX or TX */
#define TUNE_TX 0x00
#define TUNE_RX 0x01
/* For Change_DCM_FreqMode Function */
#define CHANGE_TX 0x00
#define CHANGE_RX 0x01
#define DCM_HIGH_FREQUENCY_MODE 0x00
#define DCM_LOW_FREQUENCY_MODE 0x01
#define DCM_HIGH_FREQUENCY_MODE_SET 0x0C
#define DCM_Low_FREQUENCY_MODE_SET 0x00
/* For Change_FPGA_SSCClock Function */
#define MULTIPLY_BY_1 0x00
#define MULTIPLY_BY_2 0x01
#define MULTIPLY_BY_3 0x02
#define MULTIPLY_BY_4 0x03
#define MULTIPLY_BY_5 0x04
#define MULTIPLY_BY_6 0x05
#define MULTIPLY_BY_7 0x06
#define MULTIPLY_BY_8 0x07
#define MULTIPLY_BY_9 0x08
#define MULTIPLY_BY_10 0x09
#define DIVIDE_BY_2 0x01
#define DIVIDE_BY_3 0x02
#define DIVIDE_BY_4 0x03
#define DIVIDE_BY_5 0x04
#define DIVIDE_BY_6 0x05
#define DIVIDE_BY_7 0x06
#define DIVIDE_BY_8 0x07
#define DIVIDE_BY_9 0x08
#define DIVIDE_BY_10 0x09
#define CHECK_SD_TRANS_FAIL(chip, retval) \
(((retval) != STATUS_SUCCESS) || \
(chip->rsp_buf[0] & SD_TRANSFER_ERR))
/* SD Tuning Data Structure */
/* Record continuous timing phase path */
struct timing_phase_path {
int start;
int end;
int mid;
int len;
};
int sd_select_card(struct rts51x_chip *chip, int select);
int reset_sd_card(struct rts51x_chip *chip);
int sd_switch_clock(struct rts51x_chip *chip);
void sd_stop_seq_mode(struct rts51x_chip *chip);
int sd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
void sd_cleanup_work(struct rts51x_chip *chip);
int sd_power_off_card3v3(struct rts51x_chip *chip);
int release_sd_card(struct rts51x_chip *chip);
#ifdef SUPPORT_SD_LOCK
int sd_update_lock_status(struct rts51x_chip *chip);
#endif
#ifdef SUPPORT_CPRM
extern int reset_sd(struct rts51x_chip *chip);
extern int sd_check_data0_status(struct rts51x_chip *chip);
extern int sd_read_data(struct rts51x_chip *chip, u8 trans_mode, u8 *cmd,
int cmd_len, u16 byte_cnt, u16 blk_cnt, u8 bus_width,
u8 *buf, int buf_len, int timeout);
#endif
#endif /* __RTS51X_SD_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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 "rts51x_chip.h"
#include "sd.h"
#ifdef SUPPORT_CPRM
static inline int get_rsp_type(u8 rsp_code, u8 *rsp_type, int *rsp_len)
{
if (!rsp_type || !rsp_len)
return STATUS_FAIL;
switch (rsp_code) {
case 0x03:
*rsp_type = SD_RSP_TYPE_R0; /* no response */
*rsp_len = 0;
break;
case 0x04:
*rsp_type = SD_RSP_TYPE_R1; /* R1,R6(,R4,R5) */
*rsp_len = 6;
break;
case 0x05:
*rsp_type = SD_RSP_TYPE_R1b; /* R1b */
*rsp_len = 6;
break;
case 0x06:
*rsp_type = SD_RSP_TYPE_R2; /* R2 */
*rsp_len = 17;
break;
case 0x07:
*rsp_type = SD_RSP_TYPE_R3; /* R3 */
*rsp_len = 6;
break;
default:
return STATUS_FAIL;
}
return STATUS_SUCCESS;
}
int soft_reset_sd_card(struct rts51x_chip *chip)
{
return reset_sd(chip);
}
int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
int special_check)
{
int retval;
int timeout = 50;
u16 reg_addr;
u8 buf[17], stat;
int len = 2;
int rty_cnt = 0;
RTS51X_DEBUGP("EXT SD/MMC CMD %d\n", cmd_idx);
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
RTY_SEND_CMD:
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8) (arg >> 24));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8) (arg >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8) (arg >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8) arg);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER,
0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER, SD_TRANSFER_END,
SD_TRANSFER_END);
rts51x_add_cmd(chip, READ_REG_CMD, SD_STAT1, 0, 0);
if (CHECK_USB(chip, USB_20)) {
if (rsp_type == SD_RSP_TYPE_R2) {
for (reg_addr = PPBUF_BASE2;
reg_addr < PPBUF_BASE2 + 16; reg_addr++) {
rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0,
0);
}
len = 19;
} else if (rsp_type != SD_RSP_TYPE_R0) {
/* Read data from SD_CMDx registers */
for (reg_addr = SD_CMD0; reg_addr <= SD_CMD4;
reg_addr++) {
rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0,
0);
}
len = 8;
} else {
len = 3;
}
rts51x_add_cmd(chip, READ_REG_CMD, SD_CMD5, 0, 0);
} else {
len = 2;
}
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, len, timeout);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
rts51x_clear_sd_error(chip);
if (retval == STATUS_TIMEDOUT) {
if (rsp_type & SD_WAIT_BUSY_END) {
retval = sd_check_data0_status(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
}
TRACE_RET(chip, STATUS_FAIL);
}
if (rsp_type == SD_RSP_TYPE_R0)
return STATUS_SUCCESS;
if (CHECK_USB(chip, USB_20)) {
rts51x_read_rsp_buf(chip, 2, buf, len - 2);
} else {
if (rsp_type == SD_RSP_TYPE_R2) {
reg_addr = PPBUF_BASE2;
len = 16;
} else {
reg_addr = SD_CMD0;
len = 5;
}
retval =
rts51x_seq_read_register(chip, reg_addr,
(unsigned short)len, buf);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_READ_REG(chip, SD_CMD5, buf + len);
}
stat = chip->rsp_buf[1];
if ((buf[0] & 0xC0) != 0)
TRACE_RET(chip, STATUS_FAIL);
if (!(rsp_type & SD_NO_CHECK_CRC7)) {
if (stat & SD_CRC7_ERR) {
if (cmd_idx == WRITE_MULTIPLE_BLOCK)
TRACE_RET(chip, STATUS_FAIL);
if (rty_cnt < SD_MAX_RETRY_COUNT) {
wait_timeout(20);
rty_cnt++;
goto RTY_SEND_CMD;
} else {
TRACE_RET(chip, STATUS_FAIL);
}
}
}
if ((cmd_idx == SELECT_CARD) || (cmd_idx == APP_CMD) ||
(cmd_idx == SEND_STATUS) || (cmd_idx == STOP_TRANSMISSION)) {
if ((cmd_idx != STOP_TRANSMISSION) && (special_check == 0)) {
if (buf[1] & 0x80)
TRACE_RET(chip, STATUS_FAIL);
}
#ifdef SUPPORT_SD_LOCK
if (buf[1] & 0x7D) {
#else
if (buf[1] & 0x7F) {
#endif
TRACE_RET(chip, STATUS_FAIL);
}
if (buf[2] & 0xF8)
TRACE_RET(chip, STATUS_FAIL);
if (cmd_idx == SELECT_CARD) {
if (rsp_type == SD_RSP_TYPE_R2) {
if ((buf[3] & 0x1E) != 0x04)
TRACE_RET(chip, STATUS_FAIL);
} else if (rsp_type == SD_RSP_TYPE_R2) {
if ((buf[3] & 0x1E) != 0x03)
TRACE_RET(chip, STATUS_FAIL);
}
}
}
if (rsp && rsp_len)
memcpy(rsp, buf, rsp_len);
return STATUS_SUCCESS;
}
int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 * rsp, u8 rsp_type)
{
int retval, rsp_len;
u16 reg_addr;
if (rsp_type == SD_RSP_TYPE_R0)
return STATUS_SUCCESS;
rts51x_init_cmd(chip);
if (rsp_type == SD_RSP_TYPE_R2) {
for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16;
reg_addr++) {
rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0);
}
rsp_len = 17;
} else if (rsp_type != SD_RSP_TYPE_R0) {
for (reg_addr = SD_CMD0; reg_addr <= SD_CMD4; reg_addr++)
rts51x_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0);
rsp_len = 6;
}
rts51x_add_cmd(chip, READ_REG_CMD, SD_CMD5, 0xFF, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, rsp_len, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (rsp) {
int min_len = (rsp_len < len) ? rsp_len : len;
memcpy(rsp, rts51x_get_rsp_data(chip), min_len);
RTS51X_DEBUGP("min_len = %d\n", min_len);
RTS51X_DEBUGP("Response in cmd buf: 0x%x 0x%x 0x%x 0x%x\n",
rsp[0], rsp[1], rsp[2], rsp[3]);
}
return STATUS_SUCCESS;
}
int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun,
u8 cmd_idx, u8 standby, u8 acmd, u8 rsp_code,
u32 arg)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval, rsp_len;
u8 rsp_type;
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
sd_card->last_rsp_type = rsp_type;
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
if (CHK_MMC_8BIT(sd_card)) {
retval =
rts51x_write_register(chip, SD_CFG1, 0x03,
SD_BUS_WIDTH_8);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
retval =
rts51x_write_register(chip, SD_CFG1, 0x03,
SD_BUS_WIDTH_4);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
#else
/* Set H/W SD/MMC Bus Width */
rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
#endif
if (standby) {
retval = sd_select_card(chip, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
}
if (acmd) {
retval =
ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
}
retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type,
sd_card->rsp, rsp_len, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
if (standby) {
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
}
#ifdef SUPPORT_SD_LOCK
/* Get SD lock status */
retval = sd_update_lock_status(chip);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
#endif
return TRANSPORT_GOOD;
SD_Execute_Cmd_Failed:
sd_card->pre_cmd_err = 1;
set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
release_sd_card(chip);
do_reset_sd_card(chip);
if (!(chip->card_ready & SD_CARD))
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
int ext_sd_execute_read_data(struct rts51x_chip *chip, unsigned int lun,
u8 cmd_idx, u8 cmd12, u8 standby,
u8 acmd, u8 rsp_code, u32 arg, u32 data_len,
void *data_buf, unsigned int buf_len, int use_sg)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval, rsp_len, i;
int cmd13_checkbit = 0, read_err = 0;
u8 rsp_type, bus_width;
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
sd_card->last_rsp_type = rsp_type;
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
if (CHK_MMC_8BIT(sd_card))
bus_width = SD_BUS_WIDTH_8;
else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card))
bus_width = SD_BUS_WIDTH_4;
else
bus_width = SD_BUS_WIDTH_1;
} else {
bus_width = SD_BUS_WIDTH_4;
}
RTS51X_DEBUGP("bus_width = %d\n", bus_width);
#else
bus_width = SD_BUS_WIDTH_4;
#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
if (standby) {
retval = sd_select_card(chip, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
if (acmd) {
retval =
ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
if (data_len <= 512) {
int min_len;
u8 *buf;
u16 byte_cnt, blk_cnt;
u8 cmd[5];
unsigned int offset = 0;
void *sg = NULL;
byte_cnt = (u16) (data_len & 0x3FF);
blk_cnt = 1;
cmd[0] = 0x40 | cmd_idx;
cmd[1] = (u8) (arg >> 24);
cmd[2] = (u8) (arg >> 16);
cmd[3] = (u8) (arg >> 8);
cmd[4] = (u8) arg;
buf = kmalloc(data_len, GFP_KERNEL);
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, byte_cnt,
blk_cnt, bus_width, buf, data_len, 2000);
if (retval != STATUS_SUCCESS) {
read_err = 1;
kfree(buf);
rts51x_write_register(chip, CARD_STOP,
SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
min_len = min(data_len, buf_len);
if (use_sg)
rts51x_access_sglist(buf, min_len, (void *)data_buf,
&sg, &offset, TO_XFER_BUF);
else
memcpy(data_buf, buf, min_len);
kfree(buf);
} else if (!(data_len & 0x1FF)) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H,
0xFF, (u8) (data_len >> 17));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L,
0xFF, (u8) ((data_len & 0x0001FE00) >> 9));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD0, 0xFF,
0x40 | cmd_idx);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD1, 0xFF,
(u8) (arg >> 24));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD2, 0xFF,
(u8) (arg >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD3, 0xFF,
(u8) (arg >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8) arg);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG1, 0x03, bus_width);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
trans_dma_enable(DMA_FROM_DEVICE, chip, data_len, DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_READ_2 | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CDIR, 100);
if (retval != STATUS_SUCCESS) {
read_err = 1;
rts51x_ep0_write_register(chip, CARD_STOP,
SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
retval =
rts51x_transfer_data_rcc(chip, RCV_BULK_PIPE(chip),
data_buf, buf_len, use_sg, NULL,
10000, STAGE_DI);
if (retval != STATUS_SUCCESS) {
read_err = 1;
rts51x_ep0_write_register(chip, CARD_STOP,
SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
retval = rts51x_get_rsp(chip, 1, 500);
if (CHECK_SD_TRANS_FAIL(chip, retval)) {
read_err = 1;
rts51x_ep0_write_register(chip, CARD_STOP,
SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
} else {
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
retval = ext_sd_get_rsp(chip, rsp_len, sd_card->rsp, rsp_type);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
if (standby) {
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
if (cmd12) {
retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION,
0, SD_RSP_TYPE_R1b, NULL, 0,
0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
}
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
rts51x_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02);
rts51x_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
}
if (standby || cmd12)
cmd13_checkbit = 1;
for (i = 0; i < 3; i++) {
retval =
ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0,
cmd13_checkbit);
if (retval == STATUS_SUCCESS)
break;
}
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed);
return TRANSPORT_GOOD;
SD_Execute_Read_Cmd_Failed:
sd_card->pre_cmd_err = 1;
set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
if (read_err)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
release_sd_card(chip);
do_reset_sd_card(chip);
if (!(chip->card_ready & SD_CARD))
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
u8 cmd_idx, u8 cmd12, u8 standby, u8 acmd,
u8 rsp_code, u32 arg, u32 data_len,
void *data_buf, unsigned int buf_len, int use_sg)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval, rsp_len;
int cmd13_checkbit = 0, write_err = 0;
u8 rsp_type;
u32 i;
#ifdef SUPPORT_SD_LOCK
int lock_cmd_fail = 0;
u8 sd_lock_state = 0;
u8 lock_cmd_type = 0;
#endif
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
#ifdef SUPPORT_SD_LOCK
if (cmd_idx == LOCK_UNLOCK) {
sd_lock_state = sd_card->sd_lock_status;
sd_lock_state &= SD_LOCKED;
}
#endif
retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
sd_card->last_rsp_type = rsp_type;
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
#ifdef SUPPORT_SD_LOCK
if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
if (CHK_MMC_8BIT(sd_card)) {
retval =
rts51x_write_register(chip, SD_CFG1, 0x03,
SD_BUS_WIDTH_8);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
} else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
retval =
rts51x_write_register(chip, SD_CFG1, 0x03,
SD_BUS_WIDTH_4);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
}
}
#else
rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
if (standby) {
retval = sd_select_card(chip, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
if (acmd) {
retval =
ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type,
sd_card->rsp, rsp_len, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
if (data_len <= 512) {
u8 *buf;
unsigned int offset = 0;
void *sg = NULL;
buf = kmalloc(data_len, GFP_KERNEL);
if (buf == NULL)
TRACE_RET(chip, TRANSPORT_ERROR);
if (use_sg)
rts51x_access_sglist(buf, data_len, (void *)data_buf,
&sg, &offset, FROM_XFER_BUF);
else
memcpy(buf, data_buf, data_len);
#ifdef SUPPORT_SD_LOCK
if (cmd_idx == LOCK_UNLOCK)
lock_cmd_type = buf[0] & 0x0F;
#endif
if (data_len > 256) {
rts51x_init_cmd(chip);
for (i = 0; i < 256; i++) {
rts51x_add_cmd(chip, WRITE_REG_CMD,
(u16) (PPBUF_BASE2 + i), 0xFF,
buf[i]);
}
retval = rts51x_send_cmd(chip, MODE_C, 250);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
rts51x_init_cmd(chip);
for (i = 256; i < data_len; i++) {
rts51x_add_cmd(chip, WRITE_REG_CMD,
(u16) (PPBUF_BASE2 + i), 0xFF,
buf[i]);
}
retval = rts51x_send_cmd(chip, MODE_C, 250);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
} else {
rts51x_init_cmd(chip);
for (i = 0; i < data_len; i++) {
rts51x_add_cmd(chip, WRITE_REG_CMD,
(u16) (PPBUF_BASE2 + i), 0xFF,
buf[i]);
}
retval = rts51x_send_cmd(chip, MODE_C, 250);
if (retval != STATUS_SUCCESS) {
kfree(buf);
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
}
kfree(buf);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF,
(u8) ((data_len >> 8) & 0x03));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF,
(u8) data_len);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x01);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
retval = rts51x_get_rsp(chip, 1, 250);
if (CHECK_SD_TRANS_FAIL(chip, retval))
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
} else if (!(data_len & 0x1FF)) {
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H,
0xFF, (u8) (data_len >> 17));
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L,
0xFF, (u8) ((data_len & 0x0001FE00) >> 9));
trans_dma_enable(DMA_TO_DEVICE, chip, data_len, DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
SD_TM_AUTO_WRITE_3 | SD_TRANSFER_START);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CDOR, 100);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
retval =
rts51x_transfer_data_rcc(chip, SND_BULK_PIPE(chip),
data_buf, buf_len, use_sg, NULL,
10000, STAGE_DO);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
retval = rts51x_get_rsp(chip, 1, 10000);
if (CHECK_SD_TRANS_FAIL(chip, retval))
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
} else {
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
if (retval < 0) {
write_err = 1;
rts51x_write_register(chip, CARD_STOP, SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
#ifdef SUPPORT_SD_LOCK
if (cmd_idx == LOCK_UNLOCK) {
if (lock_cmd_type == SD_ERASE) {
sd_card->sd_erase_status = SD_UNDER_ERASING;
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS,
SD_DAT0_STATUS);
retval = rts51x_send_cmd(chip, MODE_CR, 250);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
rts51x_get_rsp(chip, 1, 200); /* Don't care return value */
retval = sd_update_lock_status(chip);
if (retval != STATUS_SUCCESS) {
RTS51X_DEBUGP("Lock command fail!\n");
lock_cmd_fail = 1;
}
}
#endif /* SUPPORT_SD_LOCK */
if (standby) {
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
if (cmd12) {
retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION,
0, SD_RSP_TYPE_R1b, NULL, 0,
0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200,
SD_RSP_TYPE_R1, NULL, 0, 0);
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
rts51x_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02);
rts51x_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00);
}
if (cmd12 || standby) {
/* There is CMD7 or CMD12 sent before CMD13 */
cmd13_checkbit = 1;
}
for (i = 0; i < 3; i++) {
retval =
ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
SD_RSP_TYPE_R1, NULL, 0,
cmd13_checkbit);
if (retval == STATUS_SUCCESS)
break;
}
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
#ifdef SUPPORT_SD_LOCK
if (cmd_idx == LOCK_UNLOCK) {
if (!lock_cmd_fail) {
RTS51X_DEBUGP("lock_cmd_type = 0x%x\n",
lock_cmd_type);
if (lock_cmd_type & SD_CLR_PWD)
sd_card->sd_lock_status &= ~SD_PWD_EXIST;
if (lock_cmd_type & SD_SET_PWD)
sd_card->sd_lock_status |= SD_PWD_EXIST;
}
RTS51X_DEBUGP("sd_lock_state = 0x%x,"
"sd_card->sd_lock_status = 0x%x\n",
sd_lock_state, sd_card->sd_lock_status);
if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) {
sd_card->sd_lock_notify = 1;
if (sd_lock_state) {
if (sd_card->sd_lock_status &
SD_LOCK_1BIT_MODE) {
sd_card->sd_lock_status |=
(SD_UNLOCK_POW_ON | SD_SDR_RST);
if (CHK_SD(sd_card)) {
retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
sd_card->sd_lock_status
&= ~(SD_UNLOCK_POW_ON |
SD_SDR_RST);
TRACE_GOTO(chip,
SD_Execute_Write_Cmd_Failed);
}
}
sd_card->sd_lock_status &=
~(SD_UNLOCK_POW_ON | SD_SDR_RST);
}
}
}
}
if (lock_cmd_fail) {
scsi_set_resid(srb, 0);
set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
#endif /* SUPPORT_SD_LOCK */
return TRANSPORT_GOOD;
SD_Execute_Write_Cmd_Failed:
sd_card->pre_cmd_err = 1;
set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
if (write_err)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
release_sd_card(chip);
do_reset_sd_card(chip);
if (!(chip->card_ready & SD_CARD))
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, TRANSPORT_FAILED);
}
int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
unsigned int lun = SCSI_LUN(srb);
int len;
u8 buf[18] = {
0x00,
0x00,
0x00,
0x0E,
0x00, /* Version Number */
0x00, /* WP | Media Type */
0x00, /* RCA (Low byte) */
0x00, /* RCA (High byte) */
0x53, /* 'S' */
0x44, /* 'D' */
0x20, /* ' ' */
0x43, /* 'C' */
0x61, /* 'a' */
0x72, /* 'r' */
0x64, /* 'd' */
0x00, /* Max LUN Number */
0x00,
0x00,
};
sd_card->pre_cmd_err = 0;
if (!(CHK_BIT(chip->lun_mc, lun))) {
SET_BIT(chip->lun_mc, lun);
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((0x53 != srb->cmnd[2]) || (0x44 != srb->cmnd[3])
|| (0x20 != srb->cmnd[4]) || (0x43 != srb->cmnd[5])
|| (0x61 != srb->cmnd[6]) || (0x72 != srb->cmnd[7])
|| (0x64 != srb->cmnd[8])) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
switch (srb->cmnd[1] & 0x0F) {
case 0:
sd_card->sd_pass_thru_en = 0;
break;
case 1:
sd_card->sd_pass_thru_en = 1;
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
/* 0x01:SD Memory Card; 0x02:Other Media; 0x03:Illegal Media; */
buf[5] = (1 == CHK_SD(sd_card)) ? 0x01 : 0x02;
if (chip->card_wp & SD_CARD)
buf[5] |= 0x80;
buf[6] = (u8) (sd_card->sd_addr >> 16);
buf[7] = (u8) (sd_card->sd_addr >> 24);
buf[15] = chip->max_lun;
len = min(18, (int)scsi_bufflen(srb));
rts51x_set_xfer_buf(buf, len, srb);
return TRANSPORT_GOOD;
}
int sd_execute_no_data(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
unsigned int lun = SCSI_LUN(srb);
int retval;
u8 cmd_idx, rsp_code;
u8 standby = 0, acmd = 0;
u32 arg;
if (!sd_card->sd_pass_thru_en) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
cmd_idx = srb->cmnd[2] & 0x3F;
if (srb->cmnd[1] & 0x02)
standby = 1;
if (srb->cmnd[1] & 0x01)
acmd = 1;
arg = ((u32) srb->cmnd[3] << 24) | ((u32) srb->cmnd[4] << 16) |
((u32) srb->cmnd[5] << 8) | srb->cmnd[6];
rsp_code = srb->cmnd[10];
retval =
ext_sd_execute_no_data(chip, lun, cmd_idx, standby, acmd, rsp_code,
arg);
scsi_set_resid(srb, 0);
return retval;
}
int sd_execute_read_data(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
unsigned int lun = SCSI_LUN(srb);
u8 cmd_idx, rsp_code, send_cmd12 = 0, standby = 0, acmd = 0;
u32 arg, data_len;
if (!sd_card->sd_pass_thru_en) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
cmd_idx = srb->cmnd[2] & 0x3F;
if (srb->cmnd[1] & 0x04)
send_cmd12 = 1;
if (srb->cmnd[1] & 0x02)
standby = 1;
if (srb->cmnd[1] & 0x01)
acmd = 1;
arg = ((u32) srb->cmnd[3] << 24) | ((u32) srb->cmnd[4] << 16) |
((u32) srb->cmnd[5] << 8) | srb->cmnd[6];
data_len =
((u32) srb->cmnd[7] << 16) | ((u32) srb->cmnd[8] << 8) |
srb->cmnd[9];
rsp_code = srb->cmnd[10];
retval =
ext_sd_execute_read_data(chip, lun, cmd_idx, send_cmd12, standby,
acmd, rsp_code, arg, data_len,
scsi_sglist(srb), scsi_bufflen(srb),
scsi_sg_count(srb));
scsi_set_resid(srb, 0);
return retval;
}
int sd_execute_write_data(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
unsigned int lun = SCSI_LUN(srb);
u8 cmd_idx, rsp_code, send_cmd12 = 0, standby = 0, acmd = 0;
u32 data_len, arg;
if (!sd_card->sd_pass_thru_en) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
cmd_idx = srb->cmnd[2] & 0x3F;
if (srb->cmnd[1] & 0x04)
send_cmd12 = 1;
if (srb->cmnd[1] & 0x02)
standby = 1;
if (srb->cmnd[1] & 0x01)
acmd = 1;
data_len =
((u32) srb->cmnd[7] << 16) | ((u32) srb->cmnd[8] << 8) |
srb->cmnd[9];
arg =
((u32) srb->cmnd[3] << 24) | ((u32) srb->cmnd[4] << 16) |
((u32) srb->cmnd[5] << 8) | srb->cmnd[6];
rsp_code = srb->cmnd[10];
retval =
ext_sd_execute_write_data(chip, lun, cmd_idx, send_cmd12, standby,
acmd, rsp_code, arg, data_len,
scsi_sglist(srb), scsi_bufflen(srb),
scsi_sg_count(srb));
scsi_set_resid(srb, 0);
return retval;
}
int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
unsigned int lun = SCSI_LUN(srb);
int count;
u16 data_len;
if (!sd_card->sd_pass_thru_en) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
data_len = ((u16) srb->cmnd[7] << 8) | srb->cmnd[8];
if (sd_card->last_rsp_type == SD_RSP_TYPE_R0) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
} else if (sd_card->last_rsp_type == SD_RSP_TYPE_R2) {
count = (data_len < 17) ? data_len : 17;
} else {
count = (data_len < 6) ? data_len : 6;
}
rts51x_set_xfer_buf(sd_card->rsp, count, srb);
RTS51X_DEBUGP("Response length: %d\n", data_len);
RTS51X_DEBUGP("Response: 0x%x 0x%x 0x%x 0x%x\n",
sd_card->rsp[0], sd_card->rsp[1], sd_card->rsp[2],
sd_card->rsp[3]);
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
int sd_hw_rst(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
unsigned int lun = SCSI_LUN(srb);
int retval;
if (!sd_card->sd_pass_thru_en) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
TRACE_RET(chip, TRANSPORT_FAILED);
}
if ((0x53 != srb->cmnd[2]) || (0x44 != srb->cmnd[3])
|| (0x20 != srb->cmnd[4]) || (0x43 != srb->cmnd[5])
|| (0x61 != srb->cmnd[6]) || (0x72 != srb->cmnd[7])
|| (0x64 != srb->cmnd[8])) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
switch (srb->cmnd[1] & 0x0F) {
case 0:
/* SD Card Power Off -> ON and Initialization */
#ifdef SUPPORT_SD_LOCK
if (0x64 == srb->cmnd[9]) {
/* Command Mode */
sd_card->sd_lock_status |= SD_SDR_RST;
}
#endif /* SUPPORT_SD_LOCK */
retval = reset_sd_card(chip);
if (retval != STATUS_SUCCESS) {
#ifdef SUPPORT_SD_LOCK
sd_card->sd_lock_status &= ~SD_SDR_RST;
#endif
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
TRACE_RET(chip, TRANSPORT_FAILED);
}
#ifdef SUPPORT_SD_LOCK
sd_card->sd_lock_status &= ~SD_SDR_RST;
#endif
break;
case 1:
/* reset CMD(CMD0) and Initialization
* (without SD Card Power Off -> ON) */
retval = soft_reset_sd_card(chip);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
TRACE_RET(chip, TRANSPORT_FAILED);
}
break;
default:
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
TRACE_RET(chip, TRANSPORT_FAILED);
}
scsi_set_resid(srb, 0);
return TRANSPORT_GOOD;
}
#endif
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_SD_CPRM_H
#define __RTS51X_SD_CPRM_H
#include "rts51x_chip.h"
#include "sd.h"
#ifdef SUPPORT_CPRM
int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun,
u8 cmd_idx, u8 standby, u8 acmd, u8 rsp_code,
u32 arg);
int ext_sd_execute_read_data(struct rts51x_chip *chip, unsigned int lun,
u8 cmd_idx, u8 cmd12, u8 standby, u8 acmd,
u8 rsp_code, u32 arg, u32 data_len, void *data_buf,
unsigned int buf_len, int use_sg);
int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
u8 cmd_idx, u8 cmd12, u8 standby, u8 acmd,
u8 rsp_code, u32 arg, u32 data_len,
void *data_buf, unsigned int buf_len, int use_sg);
int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int sd_execute_no_data(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int sd_execute_read_data(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int sd_execute_write_data(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int sd_get_cmd_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip);
int sd_hw_rst(struct scsi_cmnd *srb, struct rts51x_chip *chip);
#endif
#endif /* __RTS51X_SD_CPRM_H */
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_TRACE_H
#define __RTS51X_TRACE_H
#include "debug.h"
#define _MSG_TRACE
#ifdef _MSG_TRACE
static inline char *filename(char *path)
{
char *ptr;
if (path == NULL)
return NULL;
ptr = path;
while (*ptr != '\0') {
if ((*ptr == '\\') || (*ptr == '/'))
path = ptr + 1;
ptr++;
}
return path;
}
#define TRACE_RET(chip, ret) \
do { \
char *_file = filename((char *)__FILE__); \
RTS51X_DEBUGP("[%s][%s]:[%d]\n", _file, __func__, __LINE__); \
(chip)->trace_msg[(chip)->msg_idx].line = (u16)(__LINE__); \
strncpy((chip)->trace_msg[(chip)->msg_idx].func, \
__func__, MSG_FUNC_LEN-1); \
strncpy((chip)->trace_msg[(chip)->msg_idx].file, \
_file, MSG_FILE_LEN-1); \
get_current_time((chip)->trace_msg[(chip)->msg_idx].timeval_buf,\
TIME_VAL_LEN); \
(chip)->trace_msg[(chip)->msg_idx].valid = 1; \
(chip)->msg_idx++; \
if ((chip)->msg_idx >= TRACE_ITEM_CNT) { \
(chip)->msg_idx = 0; \
} \
return ret; \
} while (0)
#define TRACE_GOTO(chip, label) \
do { \
char *_file = filename((char *)__FILE__); \
RTS51X_DEBUGP("[%s][%s]:[%d]\n", _file, __func__, __LINE__); \
(chip)->trace_msg[(chip)->msg_idx].line = (u16)(__LINE__); \
strncpy((chip)->trace_msg[(chip)->msg_idx].func, \
__func__, MSG_FUNC_LEN-1); \
strncpy((chip)->trace_msg[(chip)->msg_idx].file, \
_file, MSG_FILE_LEN-1); \
get_current_time((chip)->trace_msg[(chip)->msg_idx].timeval_buf,\
TIME_VAL_LEN); \
(chip)->trace_msg[(chip)->msg_idx].valid = 1; \
(chip)->msg_idx++; \
if ((chip)->msg_idx >= TRACE_ITEM_CNT) { \
(chip)->msg_idx = 0; \
} \
goto label; \
} while (0)
#else
#define TRACE_RET(chip, ret) return (ret)
#define TRACE_GOTO(chip, label) goto label
#endif
#ifdef CONFIG_RTS5139_DEBUG
static inline void rts51x_dump(u8 *buf, int buf_len)
{
int i;
u8 tmp[16] = { 0 };
u8 *_ptr = buf;
for (i = 0; i < ((buf_len) / 16); i++) {
RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
_ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4],
_ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9],
_ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14],
_ptr[15]);
_ptr += 16;
}
if ((buf_len) % 16) {
memcpy(tmp, _ptr, (buf_len) % 16);
_ptr = tmp;
RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
_ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4],
_ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9],
_ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14],
_ptr[15]);
}
}
#define RTS51X_DUMP(buf, buf_len) \
rts51x_dump((u8 *)(buf), (buf_len))
#define CATCH_TRIGGER(chip) \
do { \
rts51x_ep0_write_register((chip), 0xFC31, 0x01, 0x01); \
RTS51X_DEBUGP("Catch trigger!\n"); \
} while (0)
#else
#define RTS51X_DUMP(buf, buf_len)
#define CATCH_TRIGGER(chip)
#endif
#endif /* __RTS51X_TRACE_H */
/* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@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 "debug.h"
#include "trace.h"
#include "rts51x.h"
#include "rts51x_transport.h"
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "xd.h"
static int xd_build_l2p_tbl(struct rts51x_chip *chip, int zone_no);
static int xd_init_page(struct rts51x_chip *chip, u32 phy_blk, u16 logoff,
u8 start_page, u8 end_page);
static inline void xd_set_err_code(struct rts51x_chip *chip, u8 err_code)
{
struct xd_info *xd_card = &(chip->xd_card);
xd_card->err_code = err_code;
}
static inline int xd_check_err_code(struct rts51x_chip *chip, u8 err_code)
{
struct xd_info *xd_card = &(chip->xd_card);
return (xd_card->err_code == err_code);
}
static int xd_set_init_para(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval;
if (chip->asic_code)
xd_card->xd_clock = 47;
else
xd_card->xd_clock = CLK_50;
retval = switch_clock(chip, xd_card->xd_clock);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static int xd_switch_clock(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval;
retval = rts51x_select_card(chip, XD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = switch_clock(chip, xd_card->xd_clock);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static int xd_read_id(struct rts51x_chip *chip, u8 id_cmd, u8 *id_buf,
u8 buf_len)
{
int retval, i;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_DAT, 0xFF, id_cmd);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_READ_ID);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
for (i = 0; i < 4; i++) {
rts51x_add_cmd(chip, READ_REG_CMD, (u16) (XD_ADDRESS1 + i), 0,
0);
}
retval = rts51x_send_cmd(chip, MODE_CR, 20);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 5, 20);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
if (id_buf && buf_len) {
if (buf_len > 4)
buf_len = 4;
rts51x_read_rsp_buf(chip, 1, id_buf, buf_len);
}
return STATUS_SUCCESS;
}
static void xd_assign_phy_addr(struct rts51x_chip *chip, u32 addr, u8 mode)
{
struct xd_info *xd_card = &(chip->xd_card);
switch (mode) {
case XD_RW_ADDR:
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS0, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS1, 0xFF,
(u8) addr);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS2, 0xFF,
(u8) (addr >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS3, 0xFF,
(u8) (addr >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG, 0xFF,
xd_card->addr_cycle | XD_CALC_ECC |
XD_BA_NO_TRANSFORM);
break;
case XD_ERASE_ADDR:
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS0, 0xFF,
(u8) addr);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS1, 0xFF,
(u8) (addr >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_ADDRESS2, 0xFF,
(u8) (addr >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG, 0xFF,
(xd_card->addr_cycle - 1) |
XD_CALC_ECC | XD_BA_NO_TRANSFORM);
break;
default:
break;
}
}
static int xd_read_redundant(struct rts51x_chip *chip, u32 page_addr, u8 *buf,
int buf_len)
{
int retval, i;
rts51x_init_cmd(chip);
xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_READ_REDUNDANT);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
for (i = 0; i < 6; i++) {
rts51x_add_cmd(chip, READ_REG_CMD, (u16) (XD_PAGE_STATUS + i),
0, 0);
}
for (i = 0; i < 4; i++) {
rts51x_add_cmd(chip, READ_REG_CMD, (u16) (XD_RESERVED0 + i), 0,
0);
}
rts51x_add_cmd(chip, READ_REG_CMD, XD_PARITY, 0, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 11, 500);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
if (buf && buf_len) {
if (buf_len > 11)
buf_len = 11;
rts51x_read_rsp_buf(chip, 1, buf, buf_len);
}
return STATUS_SUCCESS;
}
static int xd_read_data_from_ppb(struct rts51x_chip *chip, int offset, u8 *buf,
int buf_len)
{
int retval, i;
if (!buf || (buf_len <= 0))
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
for (i = 0; i < buf_len; i++) {
rts51x_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + offset + i, 0,
0);
}
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, buf_len, 200);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
rts51x_read_rsp_buf(chip, 0, buf, buf_len);
return STATUS_SUCCESS;
}
static int xd_read_cis(struct rts51x_chip *chip, u32 page_addr, u8 *buf,
int buf_len)
{
int retval;
u8 reg;
if (!buf || (buf_len < 10))
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, 1);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
XD_AUTO_CHK_DATA_STATUS, XD_AUTO_CHK_DATA_STATUS);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_READ_PAGES);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER,
XD_TRANSFER_END | XD_PPB_EMPTY,
XD_TRANSFER_END | XD_PPB_EMPTY);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 1, 500);
if (retval == STATUS_TIMEDOUT) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
RTS51X_READ_REG(chip, XD_PAGE_STATUS, &reg);
if (reg != XD_GPG) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
RTS51X_READ_REG(chip, XD_CTL, &reg);
if (!(reg & XD_ECC1_ERROR) || !(reg & XD_ECC1_UNCORRECTABLE)) {
retval = xd_read_data_from_ppb(chip, 0, buf, buf_len);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (reg & XD_ECC1_ERROR) { /* correctable error */
u8 ecc_bit, ecc_byte;
RTS51X_READ_REG(chip, XD_ECC_BIT1, &ecc_bit);
RTS51X_READ_REG(chip, XD_ECC_BYTE1, &ecc_byte);
RTS51X_DEBUGP("ECC_BIT1 = 0x%x, ECC_BYTE1 = 0x%x\n",
ecc_bit, ecc_byte);
if (ecc_byte < buf_len) {
RTS51X_DEBUGP("Before correct: 0x%x\n",
buf[ecc_byte]);
buf[ecc_byte] ^= (1 << ecc_bit);
RTS51X_DEBUGP("After correct: 0x%x\n",
buf[ecc_byte]);
}
}
} else if (!(reg & XD_ECC2_ERROR) || !(reg & XD_ECC2_UNCORRECTABLE)) {
RTS51X_WRITE_REG(chip, CARD_STOP, XD_STOP | XD_CLR_ERR,
XD_STOP | XD_CLR_ERR);
retval = xd_read_data_from_ppb(chip, 256, buf, buf_len);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (reg & XD_ECC2_ERROR) {
u8 ecc_bit, ecc_byte;
RTS51X_READ_REG(chip, XD_ECC_BIT2, &ecc_bit);
RTS51X_READ_REG(chip, XD_ECC_BYTE2, &ecc_byte);
RTS51X_DEBUGP("ECC_BIT2 = 0x%x, ECC_BYTE2 = 0x%x\n",
ecc_bit, ecc_byte);
if (ecc_byte < buf_len) {
RTS51X_DEBUGP("Before correct: 0x%x\n",
buf[ecc_byte]);
buf[ecc_byte] ^= (1 << ecc_bit);
RTS51X_DEBUGP("After correct: 0x%x\n",
buf[ecc_byte]);
}
}
} else {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static void xd_pull_ctl_disable(struct rts51x_chip *chip)
{
if (CHECK_PKG(chip, LQFP48)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
}
}
static void xd_pull_ctl_enable(struct rts51x_chip *chip)
{
if (CHECK_PKG(chip, LQFP48)) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xAA);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xA5);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x59);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59);
}
}
static int reset_xd(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval, i, j;
u8 id_buf[4], redunt[11];
retval = rts51x_select_card(chip, XD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS, 0xFF,
XD_PGSTS_NOT_FF);
if (chip->asic_code)
xd_pull_ctl_disable(chip);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL, 0xFF,
(FPGA_XD_PULL_CTL_EN1 & FPGA_XD_PULL_CTL_EN3));
if (!chip->option.FT2_fast_mode) {
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_INIT, XD_NO_AUTO_PWR_OFF,
0);
if (CHECK_PKG(chip, LQFP48) ||
chip->option.rts5129_D3318_off_enable) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL,
DV3318_AUTO_PWR_OFF,
DV3318_AUTO_PWR_OFF);
}
}
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, 0);
if (!chip->option.FT2_fast_mode) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
}
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (!chip->option.FT2_fast_mode) {
#ifdef SD_XD_IO_FOLLOW_PWR
if (CHECK_PKG(chip, LQFP48)
|| chip->option.rts5129_D3318_off_enable) {
rts51x_write_register(chip, CARD_PWR_CTL,
LDO_OFF, LDO_OFF);
}
#endif
wait_timeout(250);
#ifdef SD_XD_IO_FOLLOW_PWR
if (CHECK_PKG(chip, LQFP48)
|| chip->option.rts5129_D3318_off_enable) {
rts51x_init_cmd(chip);
if (chip->asic_code) {
xd_pull_ctl_enable(chip);
} else {
rts51x_add_cmd(chip, WRITE_REG_CMD,
FPGA_PULL_CTL, 0xFF,
(FPGA_XD_PULL_CTL_EN1 &
FPGA_XD_PULL_CTL_EN2));
}
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
}
#endif
retval = card_power_on(chip, XD_CARD);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
#ifdef SUPPORT_OCP
wait_timeout(50);
rts51x_get_card_status(chip, &(chip->card_status));
chip->ocp_stat = (chip->card_status >> 4) & 0x03;
if (chip->ocp_stat & (MS_OCP_NOW | MS_OCP_EVER)) {
RTS51X_DEBUGP("Over current, OCPSTAT is 0x%x\n",
chip->ocp_stat);
TRACE_RET(chip, STATUS_FAIL);
}
#endif
}
rts51x_init_cmd(chip);
if (chip->asic_code)
xd_pull_ctl_enable(chip);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL, 0xFF,
(FPGA_XD_PULL_CTL_EN1 & FPGA_XD_PULL_CTL_EN2));
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN,
XD_OUTPUT_EN);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CTL, XD_CE_DISEN, XD_CE_DISEN);
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
if (!chip->option.FT2_fast_mode)
wait_timeout(200);
retval = xd_set_init_para(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
/* Read ID to check if the timing setting is right */
for (i = 0; i < 4; i++) {
u8 xd_dat, xd_ctl;
if (monitor_card_cd(chip, XD_CARD) == CD_NOT_EXIST)
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_DTCTL, 0xFF,
XD_TIME_SETUP_STEP * 3 + XD_TIME_RW_STEP *
(2 + i + chip->option.xd_rw_step)
+ XD_TIME_RWN_STEP * (i + chip->option.xd_rwn_step));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CATCTL, 0xFF,
XD_TIME_SETUP_STEP * 3 + XD_TIME_RW_STEP * (4 +
i) + XD_TIME_RWN_STEP * (3 + i));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_RESET);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER,
XD_TRANSFER_END, XD_TRANSFER_END);
rts51x_add_cmd(chip, READ_REG_CMD, XD_DAT, 0, 0);
rts51x_add_cmd(chip, READ_REG_CMD, XD_CTL, 0, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
retval = rts51x_get_rsp(chip, 3, 100);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
xd_dat = chip->rsp_buf[1];
xd_ctl = chip->rsp_buf[2];
RTS51X_DEBUGP("XD_DAT: 0x%x, XD_CTL: 0x%x\n", xd_dat, xd_ctl);
if (((xd_dat & READY_FLAG) != READY_STATE)
|| !(xd_ctl & XD_RDY))
continue;
retval = xd_read_id(chip, READ_ID, id_buf, 4);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_DEBUGP("READ_ID: 0x%x 0x%x 0x%x 0x%x\n",
id_buf[0], id_buf[1], id_buf[2], id_buf[3]);
xd_card->device_code = id_buf[1];
switch (xd_card->device_code) {
case XD_4M_X8_512_1:
case XD_4M_X8_512_2:
xd_card->block_shift = 4; /* 16 pages per block */
xd_card->page_off = 0x0F;
xd_card->addr_cycle = 3;
xd_card->zone_cnt = 1;
xd_card->capacity = 8000; /* 500 * 2 ^ 4 */
XD_SET_4MB(xd_card);
break;
case XD_8M_X8_512:
xd_card->block_shift = 4;
xd_card->page_off = 0x0F;
xd_card->addr_cycle = 3;
xd_card->zone_cnt = 1;
xd_card->capacity = 16000; /* 1000 * 2 ^ 4 */
break;
case XD_16M_X8_512:
XD_PAGE_512(xd_card); /* 32 pages per block */
xd_card->addr_cycle = 3;
xd_card->zone_cnt = 1;
xd_card->capacity = 32000; /* 1000 * 2 ^ 5 */
break;
case XD_32M_X8_512:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 3;
xd_card->zone_cnt = 2;
xd_card->capacity = 64000; /* 2000 * 2 ^ 5 */
break;
case XD_64M_X8_512:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 4;
xd_card->zone_cnt = 4;
xd_card->capacity = 128000; /* 4000 * 2 ^ 5 */
break;
case XD_128M_X8_512:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 4;
xd_card->zone_cnt = 8;
xd_card->capacity = 256000; /* 8000 * 2 ^ 5 */
break;
case XD_256M_X8_512:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 4;
xd_card->zone_cnt = 16;
xd_card->capacity = 512000; /* 16000 * 2 ^ 5 */
break;
case XD_512M_X8:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 4;
xd_card->zone_cnt = 32;
xd_card->capacity = 1024000; /* 32000 * 2 ^ 5 */
break;
case xD_1G_X8_512:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 4;
xd_card->zone_cnt = 64;
xd_card->capacity = 2048000; /* 64000 * 2 ^ 5 */
break;
case xD_2G_X8_512:
XD_PAGE_512(xd_card);
xd_card->addr_cycle = 4;
xd_card->zone_cnt = 128;
xd_card->capacity = 4096000; /* 128000 * 2 ^ 5 */
break;
default:
continue;
}
/* Confirm timing setting */
for (j = 0; j < 10; j++) {
retval = xd_read_id(chip, READ_ID, id_buf, 4);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (id_buf[1] != xd_card->device_code)
break;
}
/* Current timing pass */
if (j == 10)
break;
}
if (i == 4) {
xd_card->block_shift = 0;
xd_card->page_off = 0;
xd_card->addr_cycle = 0;
xd_card->capacity = 0;
TRACE_RET(chip, STATUS_FAIL);
}
retval = xd_read_id(chip, READ_xD_ID, id_buf, 4);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
RTS51X_DEBUGP("READ_xD_ID: 0x%x 0x%x 0x%x 0x%x\n",
id_buf[0], id_buf[1], id_buf[2], id_buf[3]);
if (id_buf[2] != XD_ID_CODE)
TRACE_RET(chip, STATUS_FAIL);
/* Search CIS block */
for (i = 0; i < 24; i++) {
u32 page_addr;
if (monitor_card_cd(chip, XD_CARD) == CD_NOT_EXIST)
TRACE_RET(chip, STATUS_FAIL);
page_addr = (u32) i << xd_card->block_shift;
for (j = 0; j < 3; j++) {
retval = xd_read_redundant(chip, page_addr, redunt, 11);
if (retval == STATUS_SUCCESS)
break;
}
if (j == 3)
continue;
if (redunt[BLOCK_STATUS] != XD_GBLK)
continue;
j = 0;
/* Check page status */
if (redunt[PAGE_STATUS] != XD_GPG) {
for (j = 1; j <= 8; j++) {
retval =
xd_read_redundant(chip, page_addr + j,
redunt, 11);
if (retval == STATUS_SUCCESS) {
if (redunt[PAGE_STATUS] == XD_GPG)
break;
}
}
if (j == 9)
break;
}
if ((redunt[BLOCK_STATUS] == XD_GBLK)
&& (redunt[PARITY] & XD_BA1_ALL0)) {
u8 buf[10];
page_addr += j;
retval = xd_read_cis(chip, page_addr, buf, 10);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if ((buf[0] == 0x01) && (buf[1] == 0x03)
&& (buf[2] == 0xD9)
&& (buf[3] == 0x01) && (buf[4] == 0xFF)
&& (buf[5] == 0x18) && (buf[6] == 0x02)
&& (buf[7] == 0xDF) && (buf[8] == 0x01)
&& (buf[9] == 0x20)) {
xd_card->cis_block = (u16) i;
}
}
break;
}
RTS51X_DEBUGP("CIS block: 0x%x\n", xd_card->cis_block);
if (xd_card->cis_block == 0xFFFF)
TRACE_RET(chip, STATUS_FAIL);
chip->capacity[chip->card2lun[XD_CARD]] = xd_card->capacity;
return STATUS_SUCCESS;
}
static int xd_check_data_blank(u8 *redunt)
{
int i;
for (i = 0; i < 6; i++) {
if (redunt[PAGE_STATUS + i] != 0xFF)
return 0;
}
if ((redunt[PARITY] & (XD_ECC1_ALL1 | XD_ECC2_ALL1)) !=
(XD_ECC1_ALL1 | XD_ECC2_ALL1))
return 0;
for (i = 0; i < 4; i++) {
if (redunt[RESERVED0 + i] != 0xFF)
return 0;
}
return 1;
}
static u16 xd_load_log_block_addr(u8 *redunt)
{
u16 addr = 0xFFFF;
if (redunt[PARITY] & XD_BA1_BA2_EQL)
addr =
((u16) redunt[BLOCK_ADDR1_H] << 8) | redunt[BLOCK_ADDR1_L];
else if (redunt[PARITY] & XD_BA1_VALID)
addr =
((u16) redunt[BLOCK_ADDR1_H] << 8) | redunt[BLOCK_ADDR1_L];
else if (redunt[PARITY] & XD_BA2_VALID)
addr =
((u16) redunt[BLOCK_ADDR2_H] << 8) | redunt[BLOCK_ADDR2_L];
return addr;
}
static int xd_init_l2p_tbl(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int size, i;
RTS51X_DEBUGP("xd_init_l2p_tbl: zone_cnt = %d\n", xd_card->zone_cnt);
if (xd_card->zone_cnt < 1)
TRACE_RET(chip, STATUS_FAIL);
size = xd_card->zone_cnt * sizeof(struct zone_entry);
RTS51X_DEBUGP("Buffer size for l2p table is %d\n", size);
xd_card->zone = vmalloc(size);
if (!xd_card->zone)
TRACE_RET(chip, STATUS_NOMEM);
for (i = 0; i < xd_card->zone_cnt; i++) {
xd_card->zone[i].build_flag = 0;
xd_card->zone[i].l2p_table = NULL;
xd_card->zone[i].free_table = NULL;
xd_card->zone[i].get_index = 0;
xd_card->zone[i].set_index = 0;
xd_card->zone[i].unused_blk_cnt = 0;
}
return STATUS_SUCCESS;
}
static inline void free_zone(struct zone_entry *zone)
{
RTS51X_DEBUGP("free_zone\n");
if (!zone)
return;
zone->build_flag = 0;
zone->set_index = 0;
zone->get_index = 0;
zone->unused_blk_cnt = 0;
if (zone->l2p_table) {
vfree(zone->l2p_table);
zone->l2p_table = NULL;
}
if (zone->free_table) {
vfree(zone->free_table);
zone->free_table = NULL;
}
}
static void xd_set_unused_block(struct rts51x_chip *chip, u32 phy_blk)
{
struct xd_info *xd_card = &(chip->xd_card);
struct zone_entry *zone;
int zone_no;
zone_no = (int)phy_blk >> 10;
if (zone_no >= xd_card->zone_cnt) {
RTS51X_DEBUGP("Set unused block to invalid zone"
"(zone_no = %d, zone_cnt = %d)\n",
zone_no, xd_card->zone_cnt);
return;
}
zone = &(xd_card->zone[zone_no]);
if (zone->free_table == NULL) {
if (xd_build_l2p_tbl(chip, zone_no) != STATUS_SUCCESS)
return;
}
if ((zone->set_index >= XD_FREE_TABLE_CNT)
|| (zone->set_index < 0)) {
free_zone(zone);
RTS51X_DEBUGP("Set unused block fail, invalid set_index\n");
return;
}
RTS51X_DEBUGP("Set unused block to index %d\n", zone->set_index);
zone->free_table[zone->set_index++] = (u16) (phy_blk & 0x3ff);
if (zone->set_index >= XD_FREE_TABLE_CNT)
zone->set_index = 0;
zone->unused_blk_cnt++;
}
static u32 xd_get_unused_block(struct rts51x_chip *chip, int zone_no)
{
struct xd_info *xd_card = &(chip->xd_card);
struct zone_entry *zone;
u32 phy_blk;
if (zone_no >= xd_card->zone_cnt) {
RTS51X_DEBUGP("Get unused block from invalid zone"
"(zone_no = %d, zone_cnt = %d)\n",
zone_no, xd_card->zone_cnt);
TRACE_RET(chip, BLK_NOT_FOUND);
}
zone = &(xd_card->zone[zone_no]);
if ((zone->unused_blk_cnt == 0) ||
(zone->set_index == zone->get_index)) {
free_zone(zone);
RTS51X_DEBUGP("Get unused block fail,"
"no unused block available\n");
TRACE_RET(chip, BLK_NOT_FOUND);
}
if ((zone->get_index >= XD_FREE_TABLE_CNT) || (zone->get_index < 0)) {
free_zone(zone);
RTS51X_DEBUGP("Get unused block fail, invalid get_index\n");
TRACE_RET(chip, BLK_NOT_FOUND);
}
RTS51X_DEBUGP("Get unused block from index %d\n", zone->get_index);
phy_blk = zone->free_table[zone->get_index];
zone->free_table[zone->get_index++] = 0xFFFF;
if (zone->get_index >= XD_FREE_TABLE_CNT)
zone->get_index = 0;
zone->unused_blk_cnt--;
phy_blk += ((u32) (zone_no) << 10);
return phy_blk;
}
static void xd_set_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off,
u16 phy_off)
{
struct xd_info *xd_card = &(chip->xd_card);
struct zone_entry *zone;
zone = &(xd_card->zone[zone_no]);
zone->l2p_table[log_off] = phy_off;
}
static u32 xd_get_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off)
{
struct xd_info *xd_card = &(chip->xd_card);
struct zone_entry *zone;
int retval;
zone = &(xd_card->zone[zone_no]);
if (zone->l2p_table[log_off] == 0xFFFF) {
u32 phy_blk = 0;
int i;
retval = xd_delay_write(chip);
if (retval != STATUS_SUCCESS) {
RTS51X_DEBUGP("In xd_get_l2p_tbl,"
"delay write fail!\n");
TRACE_RET(chip, BLK_NOT_FOUND);
}
if (zone->unused_blk_cnt <= 0) {
RTS51X_DEBUGP("No unused block!\n");
TRACE_RET(chip, BLK_NOT_FOUND);
}
for (i = 0; i < zone->unused_blk_cnt; i++) {
phy_blk = xd_get_unused_block(chip, zone_no);
if (phy_blk == BLK_NOT_FOUND) {
RTS51X_DEBUGP("No unused block available!\n");
TRACE_RET(chip, BLK_NOT_FOUND);
}
retval =
xd_init_page(chip, phy_blk, log_off, 0,
xd_card->page_off + 1);
if (retval == STATUS_SUCCESS)
break;
}
if (i >= zone->unused_blk_cnt) {
RTS51X_DEBUGP("No good unused block available!\n");
TRACE_RET(chip, BLK_NOT_FOUND);
}
xd_set_l2p_tbl(chip, zone_no, log_off, (u16) (phy_blk & 0x3FF));
return phy_blk;
}
return (u32) zone->l2p_table[log_off] + ((u32) (zone_no) << 10);
}
int reset_xd_card(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval;
memset(xd_card, 0, sizeof(struct xd_info));
xd_card->block_shift = 0;
xd_card->page_off = 0;
xd_card->addr_cycle = 0;
xd_card->capacity = 0;
xd_card->zone_cnt = 0;
xd_card->cis_block = 0xFFFF;
xd_card->delay_write.delay_write_flag = 0;
enable_card_clock(chip, XD_CARD);
retval = reset_xd(chip);
if (retval != STATUS_SUCCESS) {
if (chip->option.reset_or_rw_fail_set_pad_drive) {
rts51x_write_register(chip, CARD_DRIVE_SEL,
SD20_DRIVE_MASK, DRIVE_8mA);
}
TRACE_RET(chip, retval);
}
retval = xd_init_l2p_tbl(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
static int xd_mark_bad_block(struct rts51x_chip *chip, u32 phy_blk)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval;
u32 page_addr;
u8 reg = 0;
RTS51X_DEBUGP("mark block 0x%x as bad block\n", phy_blk);
if (phy_blk == BLK_NOT_FOUND)
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_STATUS, 0xFF, XD_GPG);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_STATUS, 0xFF,
XD_LATER_BBLK);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_H, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_L, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR2_H, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR2_L, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED0, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED1, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED2, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_RESERVED3, 0xFF, 0xFF);
page_addr = phy_blk << xd_card->block_shift;
xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR);
/* Specify page count */
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF,
xd_card->page_off + 1);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_WRITE_REDUNDANT);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rts51x_get_rsp(chip, 1, 100);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
rts51x_ep0_read_register(chip, XD_DAT, &reg);
if (reg & PROGRAM_ERROR)
xd_set_err_code(chip, XD_PRG_ERROR);
else
xd_set_err_code(chip, XD_TO_ERROR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int xd_init_page(struct rts51x_chip *chip, u32 phy_blk, u16 logoff,
u8 start_page, u8 end_page)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval;
u32 page_addr;
u8 reg = 0;
RTS51X_DEBUGP("Init block 0x%x\n", phy_blk);
if (start_page > end_page)
TRACE_RET(chip, STATUS_FAIL);
if (phy_blk == BLK_NOT_FOUND)
TRACE_RET(chip, STATUS_FAIL);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_STATUS, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_STATUS, 0xFF, 0xFF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_H, 0xFF,
(u8) (logoff >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_L, 0xFF,
(u8) logoff);
page_addr = (phy_blk << xd_card->block_shift) + start_page;
xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG, XD_BA_TRANSFORM,
XD_BA_TRANSFORM);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF,
(end_page - start_page));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_WRITE_REDUNDANT);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
retval = rts51x_get_rsp(chip, 1, 500);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
rts51x_ep0_read_register(chip, XD_DAT, &reg);
if (reg & PROGRAM_ERROR) {
xd_mark_bad_block(chip, phy_blk);
xd_set_err_code(chip, XD_PRG_ERROR);
} else {
xd_set_err_code(chip, XD_TO_ERROR);
}
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
static int xd_copy_page(struct rts51x_chip *chip,
u32 old_blk, u32 new_blk, u8 start_page, u8 end_page)
{
struct xd_info *xd_card = &(chip->xd_card);
u32 old_page, new_page;
u8 i, reg = 0;
int retval;
RTS51X_DEBUGP("Copy page from block 0x%x to block 0x%x\n", old_blk,
new_blk);
if (start_page > end_page)
TRACE_RET(chip, STATUS_FAIL);
if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND))
TRACE_RET(chip, STATUS_FAIL);
old_page = (old_blk << xd_card->block_shift) + start_page;
new_page = (new_blk << xd_card->block_shift) + start_page;
XD_CLR_BAD_NEWBLK(xd_card);
RTS51X_WRITE_REG(chip, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
for (i = start_page; i < end_page; i++) {
if (monitor_card_cd(chip, XD_CARD) == CD_NOT_EXIST) {
RTS51X_WRITE_REG(chip, CARD_STOP, XD_STOP | XD_CLR_ERR,
XD_STOP | XD_CLR_ERR);
xd_set_err_code(chip, XD_NO_CARD);
TRACE_RET(chip, STATUS_FAIL);
}
rts51x_init_cmd(chip);
xd_assign_phy_addr(chip, old_page, XD_RW_ADDR);
/* Single page read */
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, 1);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
XD_AUTO_CHK_DATA_STATUS, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_READ_PAGES);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER,
XD_TRANSFER_END, XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR | STAGE_XD_STATUS, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 4, 500);
if ((retval != STATUS_SUCCESS) ||
(chip->rsp_buf[2] & (XD_ECC1_ERROR | XD_ECC2_ERROR))) {
rts51x_clear_xd_error(chip);
reg = 0;
rts51x_ep0_read_register(chip, XD_CTL, &reg);
if (reg & (XD_ECC1_ERROR | XD_ECC2_ERROR)) {
wait_timeout(100);
if (monitor_card_cd(chip, XD_CARD) ==
CD_NOT_EXIST) {
xd_set_err_code(chip, XD_NO_CARD);
TRACE_RET(chip, STATUS_FAIL);
}
if (((reg &
(XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE))
== (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE))
|| ((reg & (XD_ECC2_ERROR |
XD_ECC2_UNCORRECTABLE)) ==
(XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE))) {
RTS51X_WRITE_REG(chip, XD_PAGE_STATUS,
0xFF, XD_BPG);
RTS51X_WRITE_REG(chip, XD_BLOCK_STATUS,
0xFF, XD_GBLK);
XD_SET_BAD_OLDBLK(xd_card);
RTS51X_DEBUGP("old block 0x%x"
"ecc error\n", old_blk);
}
} else {
xd_set_err_code(chip, XD_TO_ERROR);
TRACE_RET(chip, STATUS_FAIL);
}
}
if (XD_CHK_BAD_OLDBLK(xd_card))
rts51x_clear_xd_error(chip);
rts51x_init_cmd(chip);
xd_assign_phy_addr(chip, new_page, XD_RW_ADDR);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, 1);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_WRITE_PAGES);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER,
XD_TRANSFER_END, XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 1, 300);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
reg = 0;
rts51x_ep0_read_register(chip, XD_DAT, &reg);
if (reg & PROGRAM_ERROR) {
xd_mark_bad_block(chip, new_blk);
xd_set_err_code(chip, XD_PRG_ERROR);
XD_SET_BAD_NEWBLK(xd_card);
} else {
xd_set_err_code(chip, XD_TO_ERROR);
}
TRACE_RET(chip, retval);
}
old_page++;
new_page++;
}
return STATUS_SUCCESS;
}
#ifdef XD_SPEEDUP
static int xd_auto_copy_page(struct rts51x_chip *chip,
u32 old_blk, u32 new_blk,
u8 start_page, u8 end_page)
{
struct xd_info *xd_card = &(chip->xd_card);
u32 old_page, new_page;
int retval;
u8 page_count;
RTS51X_DEBUGP("Auto copy page from block 0x%x to block 0x%x\n",
old_blk, new_blk);
if (start_page > end_page)
TRACE_RET(chip, STATUS_FAIL);
page_count = end_page - start_page;
if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND))
TRACE_RET(chip, STATUS_FAIL);
old_page = (old_blk << xd_card->block_shift) + start_page;
new_page = (new_blk << xd_card->block_shift) + start_page;
XD_CLR_BAD_NEWBLK(xd_card);
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WAITTIME, 0x03, WAIT_FF);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_PAGELEN, 0xFF, page_count);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR0, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR1, 0xFF,
(u8) old_page);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR2, 0xFF,
(u8) (old_page >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR3, 0xFF,
(u8) (old_page >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR4, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR0, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR1, 0xFF,
(u8) new_page);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR2, 0xFF,
(u8) (new_page >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR3, 0xFF,
(u8) (new_page >> 16));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR4, 0xFF, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
PINGPONG_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG,
XD_BA_TRANSFORM | XD_ADDR_MASK, 0 | xd_card->addr_cycle);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
XD_AUTO_CHK_DATA_STATUS, 0);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_COPY_PAGES);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_GOTO(chip, Copy_Fail);
}
retval = rts51x_get_rsp(chip, 1, 800);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_GOTO(chip, Copy_Fail);
}
return STATUS_SUCCESS;
Copy_Fail:
retval = xd_copy_page(chip, old_blk, new_blk, start_page, end_page);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
#endif
static int xd_reset_cmd(struct rts51x_chip *chip)
{
int retval;
u8 xd_dat, xd_ctl;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_RESET);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
rts51x_add_cmd(chip, READ_REG_CMD, XD_DAT, 0, 0);
rts51x_add_cmd(chip, READ_REG_CMD, XD_CTL, 0, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 3, 100);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
xd_dat = chip->rsp_buf[1];
xd_ctl = chip->rsp_buf[2];
if (((xd_dat & READY_FLAG) == READY_STATE) && (xd_ctl & XD_RDY))
return STATUS_SUCCESS;
TRACE_RET(chip, STATUS_FAIL);
}
static int xd_erase_block(struct rts51x_chip *chip, u32 phy_blk)
{
struct xd_info *xd_card = &(chip->xd_card);
u32 page_addr;
u8 reg = 0, xd_dat;
int i, retval;
if (phy_blk == BLK_NOT_FOUND)
TRACE_RET(chip, STATUS_FAIL);
page_addr = phy_blk << xd_card->block_shift;
for (i = 0; i < 3; i++) {
rts51x_init_cmd(chip);
xd_assign_phy_addr(chip, page_addr, XD_ERASE_ADDR);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_ERASE);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER,
XD_TRANSFER_END, XD_TRANSFER_END);
rts51x_add_cmd(chip, READ_REG_CMD, XD_DAT, 0, 0);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 2, 300);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
rts51x_ep0_read_register(chip, XD_DAT, &reg);
if (reg & PROGRAM_ERROR) {
xd_mark_bad_block(chip, phy_blk);
xd_set_err_code(chip, XD_PRG_ERROR);
TRACE_RET(chip, STATUS_FAIL);
} else {
xd_set_err_code(chip, XD_ERASE_FAIL);
}
retval = xd_reset_cmd(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
continue;
}
xd_dat = chip->rsp_buf[1];
if (xd_dat & PROGRAM_ERROR) {
xd_mark_bad_block(chip, phy_blk);
xd_set_err_code(chip, XD_PRG_ERROR);
TRACE_RET(chip, STATUS_FAIL);
}
return STATUS_SUCCESS;
}
xd_mark_bad_block(chip, phy_blk);
xd_set_err_code(chip, XD_ERASE_FAIL);
TRACE_RET(chip, STATUS_FAIL);
}
static int xd_build_l2p_tbl(struct rts51x_chip *chip, int zone_no)
{
struct xd_info *xd_card = &(chip->xd_card);
struct zone_entry *zone;
int retval;
u32 start, end, i;
u16 max_logoff, cur_fst_page_logoff, cur_lst_page_logoff,
ent_lst_page_logoff;
u8 redunt[11];
RTS51X_DEBUGP("xd_build_l2p_tbl: %d\n", zone_no);
if (xd_card->zone == NULL) {
retval = xd_init_l2p_tbl(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
if (xd_card->zone[zone_no].build_flag) {
RTS51X_DEBUGP("l2p table of zone %d has been built\n",
zone_no);
return STATUS_SUCCESS;
}
zone = &(xd_card->zone[zone_no]);
if (zone->l2p_table == NULL) {
zone->l2p_table = vmalloc(2000);
if (zone->l2p_table == NULL)
TRACE_GOTO(chip, Build_Fail);
}
memset((u8 *) (zone->l2p_table), 0xff, 2000);
if (zone->free_table == NULL) {
zone->free_table = vmalloc(XD_FREE_TABLE_CNT * 2);
if (zone->free_table == NULL)
TRACE_GOTO(chip, Build_Fail);
}
memset((u8 *) (zone->free_table), 0xff, XD_FREE_TABLE_CNT * 2);
if (zone_no == 0) {
if (xd_card->cis_block == 0xFFFF)
start = 0;
else
start = xd_card->cis_block + 1;
if (XD_CHK_4MB(xd_card)) {
end = 0x200;
max_logoff = 499;
} else {
end = 0x400;
max_logoff = 999;
}
} else {
start = (u32) (zone_no) << 10;
end = (u32) (zone_no + 1) << 10;
max_logoff = 999;
}
RTS51X_DEBUGP("start block 0x%x, end block 0x%x\n", start, end);
zone->set_index = zone->get_index = 0;
zone->unused_blk_cnt = 0;
for (i = start; i < end; i++) {
u32 page_addr = i << xd_card->block_shift;
u32 phy_block;
retval = xd_read_redundant(chip, page_addr, redunt, 11);
if (retval != STATUS_SUCCESS)
continue;
if (redunt[BLOCK_STATUS] != 0xFF) {
RTS51X_DEBUGP("bad block\n");
continue;
}
if (xd_check_data_blank(redunt)) {
RTS51X_DEBUGP("blank block\n");
xd_set_unused_block(chip, i);
continue;
}
cur_fst_page_logoff = xd_load_log_block_addr(redunt);
if ((cur_fst_page_logoff == 0xFFFF)
|| (cur_fst_page_logoff > max_logoff)) {
retval = xd_erase_block(chip, i);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, i);
continue;
}
if ((zone_no == 0) && (cur_fst_page_logoff == 0)
&& (redunt[PAGE_STATUS] != XD_GPG))
XD_SET_MBR_FAIL(xd_card);
if (zone->l2p_table[cur_fst_page_logoff] == 0xFFFF) {
zone->l2p_table[cur_fst_page_logoff] =
(u16) (i & 0x3FF);
continue;
}
phy_block =
zone->l2p_table[cur_fst_page_logoff] +
((u32) ((zone_no) << 10));
page_addr = ((i + 1) << xd_card->block_shift) - 1;
retval = xd_read_redundant(chip, page_addr, redunt, 11);
if (retval != STATUS_SUCCESS)
continue;
cur_lst_page_logoff = xd_load_log_block_addr(redunt);
if (cur_lst_page_logoff == cur_fst_page_logoff) {
int m;
page_addr =
((phy_block + 1) << xd_card->block_shift) - 1;
for (m = 0; m < 3; m++) {
retval =
xd_read_redundant(chip, page_addr, redunt,
11);
if (retval == STATUS_SUCCESS)
break;
}
if (m == 3) {
zone->l2p_table[cur_fst_page_logoff] =
(u16) (i & 0x3FF);
retval = xd_erase_block(chip, phy_block);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, phy_block);
continue;
}
ent_lst_page_logoff = xd_load_log_block_addr(redunt);
if (ent_lst_page_logoff != cur_fst_page_logoff) {
zone->l2p_table[cur_fst_page_logoff] =
(u16) (i & 0x3FF);
retval = xd_erase_block(chip, phy_block);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, phy_block);
continue;
} else {
retval = xd_erase_block(chip, i);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, i);
}
} else {
retval = xd_erase_block(chip, i);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, i);
}
}
if (XD_CHK_4MB(xd_card))
end = 500;
else
end = 1000;
i = 0;
for (start = 0; start < end; start++) {
if (zone->l2p_table[start] == 0xFFFF)
i++;
}
RTS51X_DEBUGP("Block count %d, invalid L2P entry %d\n", end, i);
RTS51X_DEBUGP("Total unused block: %d\n", zone->unused_blk_cnt);
if ((zone->unused_blk_cnt - i) < 1)
chip->card_wp |= XD_CARD;
zone->build_flag = 1;
return STATUS_SUCCESS;
Build_Fail:
if (zone->l2p_table) {
vfree(zone->l2p_table);
zone->l2p_table = NULL;
}
if (zone->free_table) {
vfree(zone->free_table);
zone->free_table = NULL;
}
return STATUS_FAIL;
}
static int xd_send_cmd(struct rts51x_chip *chip, u8 cmd)
{
int retval;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_DAT, 0xFF, cmd);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_SET_CMD);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval = rts51x_get_rsp(chip, 1, 200);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
static int xd_read_multiple_pages(struct rts51x_chip *chip, u32 phy_blk,
u32 log_blk, u8 start_page, u8 end_page,
u8 *buf, void **ptr, unsigned int *offset)
{
struct xd_info *xd_card = &(chip->xd_card);
u32 page_addr, new_blk;
u16 log_off;
u8 reg_val, page_cnt;
int zone_no, retval, i;
if (start_page > end_page)
TRACE_RET(chip, STATUS_FAIL);
page_cnt = end_page - start_page;
zone_no = (int)(log_blk / 1000);
log_off = (u16) (log_blk % 1000);
if ((phy_blk & 0x3FF) == 0x3FF) {
for (i = 0; i < 256; i++) {
page_addr = ((u32) i) << xd_card->block_shift;
retval = xd_read_redundant(chip, page_addr, NULL, 0);
if (retval == STATUS_SUCCESS)
break;
if (monitor_card_cd(chip, XD_CARD) == CD_NOT_EXIST) {
xd_set_err_code(chip, XD_NO_CARD);
TRACE_RET(chip, STATUS_FAIL);
}
}
}
page_addr = (phy_blk << xd_card->block_shift) + start_page;
rts51x_init_cmd(chip);
xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG, XD_PPB_TO_SIE,
XD_PPB_TO_SIE);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
RING_BUFFER);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, page_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
XD_AUTO_CHK_DATA_STATUS, XD_AUTO_CHK_DATA_STATUS);
trans_dma_enable(chip->srb->sc_data_direction, chip, page_cnt * 512,
DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_READ_PAGES);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER,
XD_TRANSFER_END | XD_PPB_EMPTY,
XD_TRANSFER_END | XD_PPB_EMPTY);
retval = rts51x_send_cmd(chip, MODE_CDIR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval =
rts51x_transfer_data_partial(chip, RCV_BULK_PIPE(chip), (void *)buf,
ptr, offset, page_cnt * 512,
scsi_sg_count(chip->srb), NULL, 2000);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
if (retval == STATUS_TIMEDOUT) {
xd_set_err_code(chip, XD_TO_ERROR);
TRACE_RET(chip, retval);
} else {
TRACE_GOTO(chip, Fail);
}
}
retval = rts51x_get_rsp(chip, 1, 200);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
if (retval == STATUS_TIMEDOUT) {
xd_set_err_code(chip, XD_TO_ERROR);
TRACE_RET(chip, retval);
} else {
TRACE_GOTO(chip, Fail);
}
}
return STATUS_SUCCESS;
Fail:
rts51x_ep0_read_register(chip, XD_PAGE_STATUS, &reg_val);
RTS51X_DEBUGP("XD_PAGE_STATUS: 0x%x\n", reg_val);
if (reg_val != XD_GPG)
xd_set_err_code(chip, XD_PRG_ERROR);
rts51x_ep0_read_register(chip, XD_CTL, &reg_val);
RTS51X_DEBUGP("XD_CTL: 0x%x\n", reg_val);
/* Handle uncorrectable ECC error */
if (((reg_val & (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE))
== (XD_ECC1_ERROR | XD_ECC1_UNCORRECTABLE))
|| ((reg_val & (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE))
== (XD_ECC2_ERROR | XD_ECC2_UNCORRECTABLE))) {
wait_timeout(100);
if (monitor_card_cd(chip, XD_CARD) == CD_NOT_EXIST) {
xd_set_err_code(chip, XD_NO_CARD);
TRACE_RET(chip, STATUS_FAIL);
}
xd_set_err_code(chip, XD_ECC_ERROR);
new_blk = xd_get_unused_block(chip, zone_no);
if (new_blk == NO_NEW_BLK) {
XD_CLR_BAD_OLDBLK(xd_card);
TRACE_RET(chip, STATUS_FAIL);
}
#ifdef XD_SPEEDUP
retval =
xd_auto_copy_page(chip, phy_blk, new_blk, 0,
xd_card->page_off + 1);
#else
retval =
xd_copy_page(chip, phy_blk, new_blk, 0,
xd_card->page_off + 1);
#endif
if (retval != STATUS_SUCCESS) {
if (!XD_CHK_BAD_NEWBLK(xd_card)) {
retval = xd_erase_block(chip, new_blk);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, new_blk);
} else {
XD_CLR_BAD_NEWBLK(xd_card);
}
XD_CLR_BAD_OLDBLK(xd_card);
TRACE_RET(chip, STATUS_FAIL);
}
xd_set_l2p_tbl(chip, zone_no, log_off, (u16) (new_blk & 0x3FF));
xd_erase_block(chip, phy_blk);
xd_mark_bad_block(chip, phy_blk);
XD_CLR_BAD_OLDBLK(xd_card);
}
TRACE_RET(chip, STATUS_FAIL);
}
static int xd_finish_write(struct rts51x_chip *chip,
u32 old_blk, u32 new_blk, u32 log_blk, u8 page_off)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval, zone_no;
u16 log_off;
RTS51X_DEBUGP("xd_finish_write, old_blk = 0x%x, new_blk = 0x%x,"
"log_blk = 0x%x\n", old_blk, new_blk, log_blk);
if (page_off > xd_card->page_off)
TRACE_RET(chip, STATUS_FAIL);
zone_no = (int)(log_blk / 1000);
log_off = (u16) (log_blk % 1000);
if (old_blk == BLK_NOT_FOUND) {
retval = xd_init_page(chip, new_blk, log_off,
page_off, xd_card->page_off + 1);
if (retval != STATUS_SUCCESS) {
retval = xd_erase_block(chip, new_blk);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, new_blk);
TRACE_RET(chip, STATUS_FAIL);
}
} else {
#ifdef XD_SPEEDUP
retval = xd_auto_copy_page(chip, old_blk, new_blk,
page_off, xd_card->page_off + 1);
#else
retval = xd_copy_page(chip, old_blk, new_blk,
page_off, xd_card->page_off + 1);
#endif
if (retval != STATUS_SUCCESS) {
if (!XD_CHK_BAD_NEWBLK(xd_card)) {
retval = xd_erase_block(chip, new_blk);
if (retval == STATUS_SUCCESS)
xd_set_unused_block(chip, new_blk);
}
XD_CLR_BAD_NEWBLK(xd_card);
TRACE_RET(chip, STATUS_FAIL);
}
retval = xd_erase_block(chip, old_blk);
if (retval == STATUS_SUCCESS) {
if (XD_CHK_BAD_OLDBLK(xd_card)) {
xd_mark_bad_block(chip, old_blk);
XD_CLR_BAD_OLDBLK(xd_card);
} else {
/* Add source block to unused block */
xd_set_unused_block(chip, old_blk);
}
} else {
xd_set_err_code(chip, XD_NO_ERROR);
XD_CLR_BAD_OLDBLK(xd_card);
}
}
/* Add target block to L2P table */
xd_set_l2p_tbl(chip, zone_no, log_off, (u16) (new_blk & 0x3FF));
return STATUS_SUCCESS;
}
static int xd_prepare_write(struct rts51x_chip *chip,
u32 old_blk, u32 new_blk, u32 log_blk, u8 page_off)
{
int retval;
RTS51X_DEBUGP("xd_prepare_write, old_blk = 0x%x, new_blk = 0x%x,"
"log_blk = 0x%x, page_off = %d\n",
old_blk, new_blk, log_blk, (int)page_off);
if (page_off) {
#ifdef XD_SPEEDUP
retval = xd_auto_copy_page(chip, old_blk, new_blk, 0, page_off);
#else
retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off);
#endif
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
static int xd_write_multiple_pages(struct rts51x_chip *chip, u32 old_blk,
u32 new_blk, u32 log_blk, u8 start_page,
u8 end_page, u8 *buf, void **ptr,
unsigned int *offset)
{
struct xd_info *xd_card = &(chip->xd_card);
u32 page_addr;
int zone_no, retval;
u16 log_off;
u8 page_cnt, reg_val;
RTS51X_DEBUGP("xd_write_multiple_pages, old_blk = 0x%x,"
"new_blk = 0x%x, log_blk = 0x%x\n",
old_blk, new_blk, log_blk);
if (start_page > end_page)
TRACE_RET(chip, STATUS_FAIL);
page_cnt = end_page - start_page;
zone_no = (int)(log_blk / 1000);
log_off = (u16) (log_blk % 1000);
page_addr = (new_blk << xd_card->block_shift) + start_page;
/* Send index command */
retval = xd_send_cmd(chip, READ1_1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
rts51x_init_cmd(chip);
/* Prepare redundant field */
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_H, 0xFF,
(u8) (log_off >> 8));
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_ADDR1_L, 0xFF,
(u8) log_off);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_BLOCK_STATUS, 0xFF, XD_GBLK);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_STATUS, 0xFF, XD_GPG);
xd_assign_phy_addr(chip, page_addr, XD_RW_ADDR);
/* Transform the block address by hardware */
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG, XD_BA_TRANSFORM,
XD_BA_TRANSFORM);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_PAGE_CNT, 0xFF, page_cnt);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
RING_BUFFER);
trans_dma_enable(chip->srb->sc_data_direction, chip, page_cnt * 512,
DMA_512);
rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
XD_TRANSFER_START | XD_WRITE_PAGES);
rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
XD_TRANSFER_END);
retval = rts51x_send_cmd(chip, MODE_CDOR, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
retval =
rts51x_transfer_data_partial(chip, SND_BULK_PIPE(chip), (void *)buf,
ptr, offset, page_cnt * 512,
scsi_sg_count(chip->srb), NULL, 2000);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
if (retval == STATUS_TIMEDOUT) {
xd_set_err_code(chip, XD_TO_ERROR);
TRACE_RET(chip, retval);
} else {
TRACE_GOTO(chip, Fail);
}
}
retval = rts51x_get_rsp(chip, 1, 200);
if (retval != STATUS_SUCCESS) {
rts51x_clear_xd_error(chip);
if (retval == STATUS_TIMEDOUT) {
xd_set_err_code(chip, XD_TO_ERROR);
TRACE_RET(chip, retval);
} else {
TRACE_GOTO(chip, Fail);
}
}
if (end_page == (xd_card->page_off + 1)) {
xd_card->delay_write.delay_write_flag = 0;
if (old_blk != BLK_NOT_FOUND) {
retval = xd_erase_block(chip, old_blk);
if (retval == STATUS_SUCCESS) {
if (XD_CHK_BAD_OLDBLK(xd_card)) {
xd_mark_bad_block(chip, old_blk);
XD_CLR_BAD_OLDBLK(xd_card);
} else {
xd_set_unused_block(chip, old_blk);
}
} else {
xd_set_err_code(chip, XD_NO_ERROR);
XD_CLR_BAD_OLDBLK(xd_card);
}
}
xd_set_l2p_tbl(chip, zone_no, log_off, (u16) (new_blk & 0x3FF));
}
return STATUS_SUCCESS;
Fail:
rts51x_ep0_read_register(chip, XD_DAT, &reg_val);
RTS51X_DEBUGP("XD_DAT: 0x%x\n", reg_val);
if (reg_val & PROGRAM_ERROR) {
xd_set_err_code(chip, XD_PRG_ERROR);
xd_mark_bad_block(chip, new_blk);
}
TRACE_RET(chip, STATUS_FAIL);
}
int xd_delay_write(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
struct xd_delay_write_tag *delay_write = &(xd_card->delay_write);
int retval;
if (delay_write->delay_write_flag) {
RTS51X_DEBUGP("xd_delay_write\n");
retval = xd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
delay_write->delay_write_flag = 0;
retval = xd_finish_write(chip,
delay_write->old_phyblock,
delay_write->new_phyblock,
delay_write->logblock,
delay_write->pageoff);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
return STATUS_SUCCESS;
}
int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt)
{
struct xd_info *xd_card = &(chip->xd_card);
unsigned int lun = SCSI_LUN(srb);
struct xd_delay_write_tag *delay_write = &(xd_card->delay_write);
int retval, zone_no;
u32 log_blk, old_blk = 0, new_blk = 0;
u16 log_off, total_sec_cnt = sector_cnt;
u8 start_page, end_page = 0, page_cnt;
u8 *buf;
void *ptr = NULL;
unsigned int offset = 0;
xd_set_err_code(chip, XD_NO_ERROR);
xd_card->counter = 0;
RTS51X_DEBUGP("xd_rw: scsi_bufflen = %d, scsi_sg_count = %d\n",
scsi_bufflen(srb), scsi_sg_count(srb));
RTS51X_DEBUGP("Data direction: %s\n",
(srb->sc_data_direction ==
DMA_TO_DEVICE) ? "write" : "read");
buf = (u8 *) scsi_sglist(srb);
retval = xd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
log_blk = start_sector >> xd_card->block_shift;
start_page = (u8) start_sector & xd_card->page_off;
zone_no = (int)(log_blk / 1000);
log_off = (u16) (log_blk % 1000);
RTS51X_DEBUGP("log_blk = 0x%x\n", log_blk);
if (xd_card->zone[zone_no].build_flag == 0) {
retval = xd_build_l2p_tbl(chip, zone_no);
if (retval != STATUS_SUCCESS) {
chip->card_fail |= XD_CARD;
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, retval);
}
}
if (srb->sc_data_direction == DMA_TO_DEVICE) {
if (delay_write->delay_write_flag &&
(delay_write->logblock == log_blk) &&
(start_page > delay_write->pageoff)) {
delay_write->delay_write_flag = 0;
if (delay_write->old_phyblock != BLK_NOT_FOUND) {
#ifdef XD_SPEEDUP
retval = xd_auto_copy_page(chip,
delay_write->old_phyblock,
delay_write->new_phyblock,
delay_write->pageoff, start_page);
#else
retval = xd_copy_page(chip,
delay_write->old_phyblock,
delay_write->new_phyblock,
delay_write->pageoff,
start_page);
#endif
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, retval);
}
}
old_blk = delay_write->old_phyblock;
new_blk = delay_write->new_phyblock;
} else if (delay_write->delay_write_flag &&
(delay_write->logblock == log_blk) &&
(start_page == delay_write->pageoff)) {
delay_write->delay_write_flag = 0;
old_blk = delay_write->old_phyblock;
new_blk = delay_write->new_phyblock;
} else {
retval = xd_delay_write(chip);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, retval);
}
old_blk = xd_get_l2p_tbl(chip, zone_no, log_off);
new_blk = xd_get_unused_block(chip, zone_no);
if ((old_blk == BLK_NOT_FOUND)
|| (new_blk == BLK_NOT_FOUND)) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, retval);
}
retval =
xd_prepare_write(chip, old_blk, new_blk, log_blk,
start_page);
if (retval != STATUS_SUCCESS) {
if (monitor_card_cd(chip, XD_CARD) ==
CD_NOT_EXIST) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, STATUS_FAIL);
}
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, retval);
}
}
} else {
retval = xd_delay_write(chip);
if (retval != STATUS_SUCCESS) {
if (monitor_card_cd(chip, XD_CARD) == CD_NOT_EXIST) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, STATUS_FAIL);
}
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, retval);
}
old_blk = xd_get_l2p_tbl(chip, zone_no, log_off);
if (old_blk == BLK_NOT_FOUND) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
}
RTS51X_DEBUGP("old_blk = 0x%x\n", old_blk);
if (srb->sc_data_direction == DMA_TO_DEVICE)
RTS51X_DEBUGP("new_blk = 0x%x\n", new_blk);
while (total_sec_cnt) {
if ((start_page + total_sec_cnt) > (xd_card->page_off + 1))
end_page = xd_card->page_off + 1;
else
end_page = start_page + (u8) total_sec_cnt;
page_cnt = end_page - start_page;
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
retval = xd_read_multiple_pages(chip, old_blk, log_blk,
start_page, end_page,
buf, &ptr, &offset);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
} else {
retval =
xd_write_multiple_pages(chip, old_blk, new_blk,
log_blk, start_page,
end_page, buf, &ptr,
&offset);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
}
total_sec_cnt -= page_cnt;
if (total_sec_cnt == 0)
break;
log_blk++;
zone_no = (int)(log_blk / 1000);
log_off = (u16) (log_blk % 1000);
if (xd_card->zone[zone_no].build_flag == 0) {
retval = xd_build_l2p_tbl(chip, zone_no);
if (retval != STATUS_SUCCESS) {
chip->card_fail |= XD_CARD;
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_NOT_PRESENT);
TRACE_RET(chip, retval);
}
}
old_blk = xd_get_l2p_tbl(chip, zone_no, log_off);
if (old_blk == BLK_NOT_FOUND) {
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
} else {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
}
TRACE_RET(chip, STATUS_FAIL);
}
if (srb->sc_data_direction == DMA_TO_DEVICE) {
new_blk = xd_get_unused_block(chip, zone_no);
if (new_blk == BLK_NOT_FOUND) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
TRACE_RET(chip, STATUS_FAIL);
}
}
start_page = 0;
}
if ((srb->sc_data_direction == DMA_TO_DEVICE) &&
(end_page != (xd_card->page_off + 1))) {
delay_write->delay_write_flag = 1;
delay_write->old_phyblock = old_blk;
delay_write->new_phyblock = new_blk;
delay_write->logblock = log_blk;
delay_write->pageoff = end_page;
}
scsi_set_resid(srb, 0);
return STATUS_SUCCESS;
}
void xd_free_l2p_tbl(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int i = 0;
if (xd_card->zone != NULL) {
for (i = 0; i < xd_card->zone_cnt; i++) {
if (xd_card->zone[i].l2p_table != NULL) {
vfree(xd_card->zone[i].l2p_table);
xd_card->zone[i].l2p_table = NULL;
}
if (xd_card->zone[i].free_table != NULL) {
vfree(xd_card->zone[i].free_table);
xd_card->zone[i].free_table = NULL;
}
}
vfree(xd_card->zone);
xd_card->zone = NULL;
}
}
void xd_cleanup_work(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
if (xd_card->delay_write.delay_write_flag) {
RTS51X_DEBUGP("xD: delay write\n");
xd_delay_write(chip);
xd_card->counter = 0;
}
}
int xd_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
rts51x_init_cmd(chip);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, XD_CLK_EN, 0);
if (chip->asic_code)
xd_pull_ctl_disable(chip);
else
rts51x_add_cmd(chip, WRITE_REG_CMD, FPGA_PULL_CTL, 0xFF, 0xDF);
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_OE, XD_OUTPUT_EN, 0);
if (!chip->option.FT2_fast_mode) {
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, POWER_MASK,
POWER_OFF);
if (CHECK_PKG(chip, LQFP48)
|| chip->option.rts5129_D3318_off_enable)
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL,
DV3318_AUTO_PWR_OFF, 0);
}
retval = rts51x_send_cmd(chip, MODE_C, 100);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
return STATUS_SUCCESS;
}
int release_xd_card(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
int retval;
RTS51X_DEBUGP("elease_xd_card\n");
chip->card_ready &= ~XD_CARD;
chip->card_fail &= ~XD_CARD;
chip->card_wp &= ~XD_CARD;
xd_card->delay_write.delay_write_flag = 0;
xd_free_l2p_tbl(chip);
rts51x_write_register(chip, SFSM_ED, HW_CMD_STOP, HW_CMD_STOP);
retval = xd_power_off_card3v3(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
if (chip->asic_code && CHECK_PKG(chip, QFN24))
wait_timeout(20);
return STATUS_SUCCESS;
}
/* Driver for Realtek RTS51xx USB card reader
* Header file
*
* 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://www.gnu.org/licenses/>.
*
* Author:
* wwang (wei_wang@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
* Maintainer:
* Edwin Rong (edwin_rong@realsil.com.cn)
* No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
*/
#ifndef __RTS51X_XD_H
#define __RTS51X_XD_H
/* Error Codes */
#define XD_NO_ERROR 0x00
#define XD_NO_MEMORY 0x80
#define XD_PRG_ERROR 0x40
#define XD_NO_CARD 0x20
#define XD_READ_FAIL 0x10
#define XD_ERASE_FAIL 0x08
#define XD_WRITE_FAIL 0x04
#define XD_ECC_ERROR 0x02
#define XD_TO_ERROR 0x01
/* XD Commands */
#define READ1_1 0x00
#define READ1_2 0x01
#define READ2 0x50
#define READ_ID 0x90
#define RESET 0xff
#define PAGE_PRG_1 0x80
#define PAGE_PRG_2 0x10
#define BLK_ERASE_1 0x60
#define BLK_ERASE_2 0xD0
#define READ_STS 0x70
#define READ_xD_ID 0x9A
#define COPY_BACK_512 0x8A
#define COPY_BACK_2K 0x85
#define READ1_1_2 0x30
#define READ1_1_3 0x35
#define CHG_DAT_OUT_1 0x05
#define RDM_DAT_OUT_1 0x05
#define CHG_DAT_OUT_2 0xE0
#define RDM_DAT_OUT_2 0xE0
#define CHG_DAT_OUT_2 0xE0
#define CHG_DAT_IN_1 0x85
#define CACHE_PRG 0x15
/* Redundant Area Related */
#define XD_EXTRA_SIZE 0x10
#define XD_2K_EXTRA_SIZE 0x40
/* Define for XD Status */
#define NOT_WRITE_PROTECTED 0x80
#define READY_STATE 0x40
#define PROGRAM_ERROR 0x01
#define PROGRAM_ERROR_N_1 0x02
#define INTERNAL_READY 0x20
#define READY_FLAG 0x5F
/* Define for device code */
#define XD_8M_X8_512 0xE6
#define XD_16M_X8_512 0x73
#define XD_32M_X8_512 0x75
#define XD_64M_X8_512 0x76
#define XD_128M_X8_512 0x79
#define XD_256M_X8_512 0x71
#define XD_128M_X8_2048 0xF1
#define XD_256M_X8_2048 0xDA
#define XD_512M_X8 0xDC
#define XD_128M_X16_2048 0xC1
#define XD_4M_X8_512_1 0xE3
#define XD_4M_X8_512_2 0xE5
#define xD_1G_X8_512 0xD3
#define xD_2G_X8_512 0xD5
#define XD_ID_CODE 0xB5
#define VENDOR_BLOCK 0xEFFF
#define CIS_BLOCK 0xDFFF
#define BLK_NOT_FOUND 0xFFFFFFFF
#define NO_NEW_BLK 0xFFFFFFFF
#define PAGE_CORRECTABLE 0x0
#define PAGE_NOTCORRECTABLE 0x1
#define NO_OFFSET 0x0
#define WITH_OFFSET 0x1
#define Sect_Per_Page 4
#define XD_ADDR_MODE_2C XD_ADDR_MODE_2A
#define ZONE0_BAD_BLOCK 23
#define NOT_ZONE0_BAD_BLOCK 24
/* Assign address mode */
#define XD_RW_ADDR 0x01
#define XD_ERASE_ADDR 0x02
/* Macro Definition */
#define XD_PAGE_512(xd_card) \
do { \
(xd_card)->block_shift = 5; \
(xd_card)->page_off = 0x1F; \
} while (0)
#define XD_SET_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag |= 0x01)
#define XD_CLR_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag &= ~0x01)
#define XD_CHK_BAD_NEWBLK(xd_card) ((xd_card)->multi_flag & 0x01)
#define XD_SET_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag |= 0x02)
#define XD_CLR_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag &= ~0x02)
#define XD_CHK_BAD_OLDBLK(xd_card) ((xd_card)->multi_flag & 0x02)
#define XD_SET_MBR_FAIL(xd_card) ((xd_card)->multi_flag |= 0x04)
#define XD_CLR_MBR_FAIL(xd_card) ((xd_card)->multi_flag &= ~0x04)
#define XD_CHK_MBR_FAIL(xd_card) ((xd_card)->multi_flag & 0x04)
#define XD_SET_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag |= 0x08)
#define XD_CLR_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag &= ~0x08)
#define XD_CHK_ECC_FLD_ERR(xd_card) ((xd_card)->multi_flag & 0x08)
#define XD_SET_4MB(xd_card) ((xd_card)->multi_flag |= 0x10)
#define XD_CLR_4MB(xd_card) ((xd_card)->multi_flag &= ~0x10)
#define XD_CHK_4MB(xd_card) ((xd_card)->multi_flag & 0x10)
#define XD_SET_ECC_ERR(xd_card) ((xd_card)->multi_flag |= 0x40)
#define XD_CLR_ECC_ERR(xd_card) ((xd_card)->multi_flag &= ~0x40)
#define XD_CHK_ECC_ERR(xd_card) ((xd_card)->multi_flag & 0x40)
/* Offset in xD redundant buffer */
#define PAGE_STATUS 0
#define BLOCK_STATUS 1
#define BLOCK_ADDR1_L 2
#define BLOCK_ADDR1_H 3
#define BLOCK_ADDR2_L 4
#define BLOCK_ADDR2_H 5
#define RESERVED0 6
#define RESERVED1 7
#define RESERVED2 8
#define RESERVED3 9
#define PARITY 10
/* For CIS block */
#define CIS0_0 0
#define CIS0_1 1
#define CIS0_2 2
#define CIS0_3 3
#define CIS0_4 4
#define CIS0_5 5
#define CIS0_6 6
#define CIS0_7 7
#define CIS0_8 8
#define CIS0_9 9
#define CIS1_0 256
#define CIS1_1 (256 + 1)
#define CIS1_2 (256 + 2)
#define CIS1_3 (256 + 3)
#define CIS1_4 (256 + 4)
#define CIS1_5 (256 + 5)
#define CIS1_6 (256 + 6)
#define CIS1_7 (256 + 7)
#define CIS1_8 (256 + 8)
#define CIS1_9 (256 + 9)
int reset_xd_card(struct rts51x_chip *chip);
int xd_delay_write(struct rts51x_chip *chip);
int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
void xd_free_l2p_tbl(struct rts51x_chip *chip);
void xd_cleanup_work(struct rts51x_chip *chip);
int xd_power_off_card3v3(struct rts51x_chip *chip);
int release_xd_card(struct rts51x_chip *chip);
#endif /* __RTS51X_XD_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment