mirror of https://gitee.com/openkylin/linux.git
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: edwin_rong <edwin_rong@realsil.com.cn> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
dd89e20d7e
commit
1dac4186bc
|
@ -64,6 +64,8 @@ source "drivers/staging/rtl8712/Kconfig"
|
|||
|
||||
source "drivers/staging/rts_pstor/Kconfig"
|
||||
|
||||
source "drivers/staging/rts5139/Kconfig"
|
||||
|
||||
source "drivers/staging/frontier/Kconfig"
|
||||
|
||||
source "drivers/staging/pohmelfs/Kconfig"
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_RTL8192U) += rtl8192u/
|
|||
obj-$(CONFIG_RTL8192E) += rtl8192e/
|
||||
obj-$(CONFIG_R8712U) += rtl8712/
|
||||
obj-$(CONFIG_RTS_PSTOR) += rts_pstor/
|
||||
obj-$(CONFIG_RTS5139) += rts5139/
|
||||
obj-$(CONFIG_SPECTRA) += spectra/
|
||||
obj-$(CONFIG_TRANZPORT) += frontier/
|
||||
obj-$(CONFIG_POHMELFS) += pohmelfs/
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
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.
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# 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
|
|
@ -0,0 +1,5 @@
|
|||
TODO:
|
||||
- support more USB card reader of Realtek family
|
||||
- use kernel coding style
|
||||
- checkpatch.pl fixes
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,263 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,642 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,41 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,967 @@
|
|||
/* 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);
|
|
@ -0,0 +1,205 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,986 @@
|
|||
/* 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;
|
||||
}
|
|
@ -0,0 +1,881 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,904 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,298 @@
|
|||
/* 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
|
|
@ -0,0 +1,62 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,162 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,54 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,80 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,304 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,54 @@
|
|||
/* 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 */
|
|
@ -0,0 +1,137 @@
|
|||
/* 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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,193 @@
|
|||
/* 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 */
|
Loading…
Reference in New Issue