/* 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
*/
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <linux/cdrom.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/usb_usual.h>
#include "usb.h"
#include "transport.h"
#include "protocol.h"
#include "debug.h"
MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.03");
static int auto_delink_en = 1;
module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
#ifdef CONFIG_REALTEK_AUTOPM
static int ss_en = 1;
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");
enum RTS51X_STAT {
RTS51X_STAT_INIT,
RTS51X_STAT_IDLE,
RTS51X_STAT_RUN,
RTS51X_STAT_SS
};
#define POLLING_INTERVAL 50
#define rts51x_set_stat(chip, stat) \
((chip)->state = (enum RTS51X_STAT)(stat))
#define rts51x_get_stat(chip) ((chip)->state)
#define SET_LUN_READY(chip, lun) ((chip)->lun_ready |= ((u8)1 << (lun)))
#define CLR_LUN_READY(chip, lun) ((chip)->lun_ready &= ~((u8)1 << (lun)))
#define TST_LUN_READY(chip, lun) ((chip)->lun_ready & ((u8)1 << (lun)))
#endif
struct rts51x_status {
u16 vid;
u16 pid;
u8 cur_lun;
u8 card_type;
u8 total_lun;
u16 fw_ver;
u8 phy_exist;
u8 multi_flag;
u8 multi_card;
u8 log_exist;
union {
u8 detailed_type1;
u8 detailed_type2;
} detailed_type;
u8 function[2];
};
struct rts51x_chip {
u16 vendor_id;
u16 product_id;
char max_lun;
struct rts51x_status *status;
int status_len;
u32 flag;
#ifdef CONFIG_REALTEK_AUTOPM
struct us_data *us;
struct timer_list rts51x_suspend_timer;
unsigned long timer_expires;
int pwr_state;
u8 lun_ready;
enum RTS51X_STAT state;
int support_auto_delink;
#endif
/* used to back up the protocal choosen in probe1 phase */
proto_cmnd proto_handler_backup;
};
/* flag definition */
#define FLIDX_AUTO_DELINK 0x01
#define SCSI_LUN(srb) ((srb)->device->lun)
/* 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)))
#define SET_AUTO_DELINK(chip) ((chip)->flag |= FLIDX_AUTO_DELINK)
#define CLR_AUTO_DELINK(chip) ((chip)->flag &= ~FLIDX_AUTO_DELINK)
#define CHK_AUTO_DELINK(chip) ((chip)->flag & FLIDX_AUTO_DELINK)
#define RTS51X_GET_VID(chip) ((chip)->vendor_id)
#define RTS51X_GET_PID(chip) ((chip)->product_id)
#define VENDOR_ID(chip) ((chip)->status[0].vid)
#define PRODUCT_ID(chip) ((chip)->status[0].pid)
#define FW_VERSION(chip) ((chip)->status[0].fw_ver)
#define STATUS_LEN(chip) ((chip)->status_len)
#define STATUS_SUCCESS 0
#define STATUS_FAIL 1
/* Check card reader function */
#define SUPPORT_DETAILED_TYPE1(chip) \
CHK_BIT((chip)->status[0].function[0], 1)
#define SUPPORT_OT(chip) \
CHK_BIT((chip)->status[0].function[0], 2)
#define SUPPORT_OC(chip) \
CHK_BIT((chip)->status[0].function[0], 3)
#define SUPPORT_AUTO_DELINK(chip) \
CHK_BIT((chip)->status[0].function[0], 4)
#define SUPPORT_SDIO(chip) \
CHK_BIT((chip)->status[0].function[1], 0)
#define SUPPORT_DETAILED_TYPE2(chip) \
CHK_BIT((chip)->status[0].function[1], 1)
#define CHECK_PID(chip, pid) (RTS51X_GET_PID(chip) == (pid))
#define CHECK_FW_VER(chip, fw_ver) (FW_VERSION(chip) == (fw_ver))
#define CHECK_ID(chip, pid, fw_ver) \
(CHECK_PID((chip), (pid)) && CHECK_FW_VER((chip), (fw_ver)))
static int init_realtek_cr(struct us_data *us);
/*
* The table of devices
*/
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
vendorName, productName, useProtocol, useTransport, \
initFunction, flags) \
{\
USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
.driver_info = (flags)|(USB_US_TYPE_STOR<<24)\
}
static const struct usb_device_id realtek_cr_ids[] = {
# include "unusual_realtek.h"
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, realtek_cr_ids);
#undef UNUSUAL_DEV
/*
* The flags table
*/
#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
vendor_name, product_name, use_protocol, use_transport, \
init_function, Flags) \
{ \
.vendorName = vendor_name, \
.productName = product_name, \
.useProtocol = use_protocol, \
.useTransport = use_transport, \
.initFunction = init_function, \
}
static struct us_unusual_dev realtek_cr_unusual_dev_list[] = {
# include "unusual_realtek.h"
{} /* Terminating entry */
};
#undef UNUSUAL_DEV
static int rts51x_bulk_transport(struct us_data *us, u8 lun,
u8 *cmd, int cmd_len, u8 *buf, int buf_len,
enum dma_data_direction dir, int *a