// SPDX-License-Identifier: GPL-2.0+
/*
* Driver for Realtek RTS51xx USB card reader
*
* Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
*
* 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"
#include "scsiglue.h"
#define DRV_NAME "ums-realtek"
MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("USB_STORAGE");
static int auto_delink_en = 1;
module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(auto_delink_en, "auto delink mode (0=firmware, 1=software [default])");
#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;
struct us_data *us;
#ifdef CONFIG_REALTEK_AUTOPM
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 protocol chosen 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) \
}
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 const 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 *act_len)
{
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *)us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *)us->iobuf;