diff options
Diffstat (limited to 'drivers/pcmcia/cs.c')
| -rw-r--r-- | drivers/pcmcia/cs.c | 116 |
1 files changed, 45 insertions, 71 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 976d80706ea..5292db69c42 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -29,12 +29,9 @@ #include <linux/device.h> #include <linux/kthread.h> #include <linux/freezer.h> -#include <asm/system.h> #include <asm/irq.h> -#include <pcmcia/cs_types.h> #include <pcmcia/ss.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> @@ -252,38 +249,6 @@ struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr) } EXPORT_SYMBOL(pcmcia_get_socket_by_nr); -/* - * The central event handler. Send_event() sends an event to the - * 16-bit subsystem, which then calls the relevant device drivers. - * Parse_events() interprets the event bits from - * a card status change report. Do_shutdown() handles the high - * priority stuff associated with a card removal. - */ - -/* NOTE: send_event needs to be called with skt->sem held. */ - -static int send_event(struct pcmcia_socket *s, event_t event, int priority) -{ - int ret; - - if ((s->state & SOCKET_CARDBUS) && (event != CS_EVENT_CARD_REMOVAL)) - return 0; - - dev_dbg(&s->dev, "send_event(event %d, pri %d, callback 0x%p)\n", - event, priority, s->callback); - - if (!s->callback) - return 0; - if (!try_module_get(s->callback->owner)) - return 0; - - ret = s->callback->event(s, event, priority); - - module_put(s->callback->owner); - - return ret; -} - static int socket_reset(struct pcmcia_socket *skt) { int status, i; @@ -326,7 +291,8 @@ static void socket_shutdown(struct pcmcia_socket *s) dev_dbg(&s->dev, "shutdown\n"); - send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); + if (s->callback) + s->callback->remove(s); mutex_lock(&s->ops_mutex); s->state &= SOCKET_INUSE | SOCKET_PRESENT; @@ -477,7 +443,8 @@ static int socket_insert(struct pcmcia_socket *skt) dev_dbg(&skt->dev, "insert done\n"); mutex_unlock(&skt->ops_mutex); - send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) + skt->callback->add(skt); } else { mutex_unlock(&skt->ops_mutex); socket_shutdown(skt); @@ -494,7 +461,6 @@ static int socket_suspend(struct pcmcia_socket *skt) mutex_lock(&skt->ops_mutex); skt->suspended_state = skt->state; - send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW); skt->socket = dead_socket; skt->ops->set_socket(skt, &skt->socket); if (skt->ops->suspend) @@ -518,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; @@ -545,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 - - send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); - return 0; + return ret; } /* @@ -567,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) @@ -654,16 +636,8 @@ static int pccardd(void *__skt) spin_unlock_irqrestore(&skt->thread_lock, flags); mutex_lock(&skt->skt_mutex); - if (events) { - if (events & SS_DETECT) - socket_detect_change(skt); - if (events & SS_BATDEAD) - send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW); - if (events & SS_BATWARN) - send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW); - if (events & SS_READY) - send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW); - } + if (events & SS_DETECT) + socket_detect_change(skt); if (sysfs_events) { if (sysfs_events & PCMCIA_UEVENT_EJECT) @@ -783,7 +757,7 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) s->callback = c; if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) - send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); + s->callback->add(s); } else s->callback = NULL; err: @@ -823,20 +797,13 @@ int pcmcia_reset_card(struct pcmcia_socket *skt) break; } - ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW); - if (ret == 0) { - send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW); - if (skt->callback) - skt->callback->suspend(skt); - mutex_lock(&skt->ops_mutex); - ret = socket_reset(skt); - mutex_unlock(&skt->ops_mutex); - if (ret == 0) { - send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); - if (skt->callback) - skt->callback->resume(skt); - } - } + if (skt->callback) + skt->callback->suspend(skt); + mutex_lock(&skt->ops_mutex); + ret = socket_reset(skt); + mutex_unlock(&skt->ops_mutex); + if ((ret == 0) && (skt->callback)) + skt->callback->resume(skt); ret = 0; } while (0); @@ -892,11 +859,17 @@ static int pcmcia_socket_dev_resume_noirq(struct device *dev) return __pcmcia_pm_op(dev, socket_early_resume); } -static int pcmcia_socket_dev_resume(struct device *dev) +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, @@ -911,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) |
