diff options
Diffstat (limited to 'drivers/pcmcia/cs.c')
| -rw-r--r-- | drivers/pcmcia/cs.c | 38 | 
1 files changed, 30 insertions, 8 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index d9ea192c400..5292db69c42 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -29,7 +29,6 @@  #include <linux/device.h>  #include <linux/kthread.h>  #include <linux/freezer.h> -#include <asm/system.h>  #include <asm/irq.h>  #include <pcmcia/ss.h> @@ -485,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt)  static int socket_late_resume(struct pcmcia_socket *skt)  { -	int ret; +	int ret = 0;  	mutex_lock(&skt->ops_mutex);  	skt->state &= ~SOCKET_SUSPEND; @@ -512,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt)  		return socket_insert(skt);  	} +	if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) +		ret = skt->callback->early_resume(skt); +	return ret; +} + +/* + * Finalize the resume. In case of a cardbus socket, we have + * to rebind the devices as we can't be certain that it has been + * replaced, or not. + */ +static int socket_complete_resume(struct pcmcia_socket *skt) +{ +	int ret = 0;  #ifdef CONFIG_CARDBUS  	if (skt->state & SOCKET_CARDBUS) {  		/* We can't be sure the CardBus card is the same  		 * as the one previously inserted. Therefore, remove  		 * and re-add... */  		cb_free(skt); -		cb_alloc(skt); -		return 0; +		ret = cb_alloc(skt); +		if (ret) +			cb_free(skt);  	}  #endif -	if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) -		skt->callback->early_resume(skt); -	return 0; +	return ret;  }  /* @@ -534,11 +545,15 @@ static int socket_late_resume(struct pcmcia_socket *skt)   */  static int socket_resume(struct pcmcia_socket *skt)  { +	int err;  	if (!(skt->state & SOCKET_SUSPEND))  		return -EBUSY;  	socket_early_resume(skt); -	return socket_late_resume(skt); +	err = socket_late_resume(skt); +	if (!err) +		err = socket_complete_resume(skt); +	return err;  }  static void socket_remove(struct pcmcia_socket *skt) @@ -849,6 +864,12 @@ static int __used pcmcia_socket_dev_resume(struct device *dev)  	return __pcmcia_pm_op(dev, socket_late_resume);  } +static void __used pcmcia_socket_dev_complete(struct device *dev) +{ +	WARN(__pcmcia_pm_op(dev, socket_complete_resume), +		"failed to complete resume"); +} +  static const struct dev_pm_ops pcmcia_socket_pm_ops = {  	/* dev_resume may be called with IRQs enabled */  	SET_SYSTEM_SLEEP_PM_OPS(NULL, @@ -863,6 +884,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = {  	.resume_noirq = pcmcia_socket_dev_resume_noirq,  	.thaw_noirq = pcmcia_socket_dev_resume_noirq,  	.restore_noirq = pcmcia_socket_dev_resume_noirq, +	.complete = pcmcia_socket_dev_complete,  };  #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)  | 
