| Index: drivers/usb/storage/realtek_cr.c
|
| diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
|
| index 6873ecec391e3808e7eac05ec1b869c29eb9d7a7..c678b91d2351c14e190328d35e8c58e28b7e9154 100644
|
| --- a/drivers/usb/storage/realtek_cr.c
|
| +++ b/drivers/usb/storage/realtek_cr.c
|
| @@ -44,12 +44,13 @@
|
| MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");
|
| MODULE_AUTHOR("wwang <wei_wang@realsil.com.cn>");
|
| MODULE_LICENSE("GPL");
|
| +MODULE_VERSION("1.02");
|
|
|
| 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 = 20;
|
| +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");
|
|
|
| @@ -61,7 +62,7 @@ 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");
|
|
|
| -enum CHIP_STAT {STAT_INIT, STAT_IDLE, STAT_RUN, STAT_SS_PRE, STAT_SS};
|
| +enum CHIP_STAT {STAT_INIT, STAT_IDLE, STAT_RUN, STAT_SS_PRE, STAT_SS, STAT_SUSPEND};
|
|
|
| struct rts51x_status {
|
| u16 vid;
|
| @@ -90,6 +91,8 @@ struct rts51x_chip {
|
| int idle_counter;
|
| enum CHIP_STAT chip_stat;
|
|
|
| + int resume_from_scsi;
|
| +
|
| struct rts51x_status *status;
|
| int status_len;
|
| u8 lun_ready;
|
| @@ -422,6 +425,8 @@ static int rts51x_check_status(struct us_data *us, u8 lun)
|
| return -EIO;
|
| }
|
|
|
| + US_DEBUGP("chip->status_len = %d\n", chip->status_len);
|
| +
|
| chip->status[lun].vid = ((u16)buf[0] << 8) | buf[1];
|
| chip->status[lun].pid = ((u16)buf[2] << 8) | buf[3];
|
| chip->status[lun].cur_lun = buf[4];
|
| @@ -655,8 +660,13 @@ static int config_autodelink_before_power_down(struct us_data *us)
|
| static void rts51x_polling_func(struct us_data *us)
|
| {
|
| struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
|
| +
|
| + /* lock the device pointers */
|
| + mutex_lock(&(us->dev_mutex));
|
|
|
| if (RTS51X_CHK_STAT(chip, STAT_SS) || RTS51X_CHK_STAT(chip, STAT_SS_PRE)) {
|
| + /* unlock the device pointers */
|
| + mutex_unlock(&(us->dev_mutex));
|
| return;
|
| }
|
|
|
| @@ -668,6 +678,9 @@ static void rts51x_polling_func(struct us_data *us)
|
| } else {
|
| US_DEBUGP("Ready to enter SS state\n");
|
| RTS51X_SET_STAT(chip, STAT_SS_PRE); // Prepare SS state
|
| +
|
| + /* unlock the device pointers */
|
| + mutex_unlock(&(us->dev_mutex));
|
| usb_autopm_enable(us->pusb_intf);
|
| return;
|
| }
|
| @@ -686,16 +699,8 @@ static void rts51x_polling_func(struct us_data *us)
|
| }
|
| }
|
|
|
| - switch (RTS51X_GET_STAT(chip)) {
|
| - case STAT_RUN:
|
| - break;
|
| -
|
| - case STAT_IDLE:
|
| - break;
|
| -
|
| - default:
|
| - break;
|
| - }
|
| + /* unlock the device pointers */
|
| + mutex_unlock(&(us->dev_mutex));
|
| }
|
|
|
| static int rts51x_polling_thread(void * __us)
|
| @@ -714,13 +719,8 @@ static int rts51x_polling_thread(void * __us)
|
| break;
|
| }
|
|
|
| - /* lock the device pointers */
|
| - mutex_lock(&(us->dev_mutex));
|
| -
|
| rts51x_polling_func(us);
|
| -
|
| - /* unlock the device pointers */
|
| - mutex_unlock(&(us->dev_mutex));
|
| +
|
| } /* for (;;) */
|
|
|
| __set_current_state(TASK_RUNNING);
|
| @@ -728,31 +728,58 @@ static int rts51x_polling_thread(void * __us)
|
| }
|
|
|
| #ifdef CONFIG_PM
|
| -static void rts51x_handle_pm(struct us_data *us, int pwr_state)
|
| +int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
|
| {
|
| + struct us_data *us = usb_get_intfdata(iface);
|
| struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
|
| +
|
| + US_DEBUGP("%s, message.event = 0x%x\n", __func__, message.event);
|
| +
|
| + /* Wait until no command is running */
|
| + mutex_lock(&us->dev_mutex);
|
|
|
| - US_DEBUGP("Handle pm state: %s\n", pwr_state ? "resume" : "suspend");
|
| + if (message.event == PM_EVENT_AUTO_SUSPEND) {
|
| + US_DEBUGP("Enter SS state");
|
| + chip->resume_from_scsi = 0;
|
| + RTS51X_SET_STAT(chip, STAT_SS);
|
| + } else {
|
| + US_DEBUGP("Enter SUSPEND state");
|
| + RTS51X_SET_STAT(chip, STAT_SUSPEND);
|
| + }
|
| + (void)config_autodelink_before_power_down(us);
|
| +
|
| + /* When runtime PM is working, we'll set a flag to indicate
|
| + * whether we should autoresume when a SCSI request arrives. */
|
| +
|
| + mutex_unlock(&us->dev_mutex);
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +int realtek_cr_resume(struct usb_interface *iface)
|
| +{
|
| + struct us_data *us = usb_get_intfdata(iface);
|
| + struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
|
| +
|
| + US_DEBUGP("%s\n", __func__);
|
| +
|
| + if (!RTS51X_CHK_STAT(chip, STAT_SS) || !chip->resume_from_scsi) {
|
| + mutex_lock(&us->dev_mutex);
|
|
|
| - if (pwr_state == US_RESUME) {
|
| if (GET_PM_USAGE_CNT(us) <= 0) {
|
| // Remote wake up, increase pm_usage_cnt
|
| US_DEBUGP("Incr pm_usage_cnt\n");
|
| SET_PM_USAGE_CNT(us, 1);
|
| - RTS51X_SET_STAT(chip, STAT_RUN);
|
| }
|
| -
|
| +
|
| (void)config_autodelink_after_power_on(us);
|
| - } else {
|
| - if (RTS51X_CHK_STAT(chip, STAT_SS_PRE)) {
|
| - US_DEBUGP("Enter SS state");
|
| - RTS51X_SET_STAT(chip, STAT_SS);
|
| - }
|
| -
|
| - (void)config_autodelink_before_power_down(us);
|
| +
|
| + RTS51X_SET_STAT(chip, STAT_RUN);
|
| +
|
| + mutex_unlock(&us->dev_mutex);
|
| }
|
|
|
| - US_DEBUGP("pm_usage_cnt = %d\n", GET_PM_USAGE_CNT(us));
|
| + return 0;
|
| }
|
| #endif
|
|
|
| @@ -786,10 +813,6 @@ static int init_realtek_cr(struct us_data *us)
|
| us->extra = chip;
|
| us->extra_destructor = realtek_cr_destructor;
|
|
|
| -#ifdef CONFIG_PM
|
| - us->suspend_resume_hook = rts51x_handle_pm;
|
| -#endif
|
| -
|
| us->max_lun = chip->max_lun = rts51x_get_max_lun(us);
|
|
|
| US_DEBUGP("chip->max_lun = %d\n", chip->max_lun);
|
| @@ -817,6 +840,8 @@ static int init_realtek_cr(struct us_data *us)
|
| }
|
| }
|
|
|
| + US_DEBUGP("chip->flag = 0x%x\n", chip->flag);
|
| +
|
| (void)config_autodelink_after_power_on(us);
|
|
|
| #ifdef CONFIG_PM
|
| @@ -895,10 +920,11 @@ static int realtek_cr_transport(struct scsi_cmnd *srb, struct us_data *us)
|
| if (RTS51X_CHK_STAT(chip, STAT_SS)) {
|
| // Wake up device
|
| US_DEBUGP("Try to wake up device\n");
|
| - mutex_unlock(&(us->dev_mutex));
|
| + chip->resume_from_scsi = 1;
|
| usb_autopm_disable(us->pusb_intf);
|
| wait_timeout(3000);
|
| - mutex_lock(&(us->dev_mutex));
|
| +
|
| + (void)config_autodelink_after_power_on(us);
|
| rts51x_reset_card(us, lun);
|
| }
|
| RTS51X_SET_STAT(chip, STAT_RUN);
|
| @@ -950,8 +976,8 @@ static struct usb_driver realtek_cr_driver = {
|
| .name = "ums-realtek",
|
| .probe = realtek_cr_probe,
|
| .disconnect = usb_stor_disconnect,
|
| - .suspend = usb_stor_suspend,
|
| - .resume = usb_stor_resume,
|
| + .suspend = realtek_cr_suspend,
|
| + .resume = realtek_cr_resume,
|
| .reset_resume = usb_stor_reset_resume,
|
| .pre_reset = usb_stor_pre_reset,
|
| .post_reset = usb_stor_post_reset,
|
|
|