diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/cs.c | 37 |
1 files changed, 30 insertions, 7 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 673c14ea11e3..5292db69c426 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -484,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; @@ -511,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; } /* @@ -533,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) @@ -848,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, @@ -862,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) |