Merge the suspend and resume methods for 16-bit PCMCIA cards into the device model -- for both runtime power management and suspend to ram/disk. Signed-off-by: Dominik Brodowski --- drivers/base/power/power.h | 17 ------- drivers/base/power/runtime.c | 2 drivers/pcmcia/cs.c | 14 +++++- drivers/pcmcia/cs_internal.h | 2 drivers/pcmcia/ds.c | 96 ++++++++++++++++++++++++++++++++++++++----- include/linux/device.h | 20 ++++++++ 6 files changed, 123 insertions(+), 28 deletions(-) Index: 2.6.13-git4/drivers/pcmcia/cs.c =================================================================== --- 2.6.13-git4.orig/drivers/pcmcia/cs.c +++ 2.6.13-git4/drivers/pcmcia/cs.c @@ -773,8 +773,13 @@ int pccard_reset_card(struct pcmcia_sock 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 (socket_reset(skt) == CS_SUCCESS) + if (skt->callback) + skt->callback->suspend(skt); + if (socket_reset(skt) == CS_SUCCESS) { send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); + if (skt->callback) + skt->callback->resume(skt); + } } ret = CS_SUCCESS; @@ -805,6 +810,11 @@ int pcmcia_suspend_card(struct pcmcia_so ret = CS_UNSUPPORTED_FUNCTION; break; } + if (skt->callback) { + ret = skt->callback->suspend(skt); + if (ret) + break; + } ret = socket_suspend(skt); } while (0); up(&skt->skt_sem); @@ -831,6 +841,8 @@ int pcmcia_resume_card(struct pcmcia_soc break; } ret = socket_resume(skt); + if (!ret && skt->callback) + skt->callback->resume(skt); } while (0); up(&skt->skt_sem); Index: 2.6.13-git4/drivers/pcmcia/cs_internal.h =================================================================== --- 2.6.13-git4.orig/drivers/pcmcia/cs_internal.h +++ 2.6.13-git4/drivers/pcmcia/cs_internal.h @@ -143,6 +143,8 @@ struct pcmcia_callback{ struct module *owner; int (*event) (struct pcmcia_socket *s, event_t event, int priority); void (*requery) (struct pcmcia_socket *s); + int (*suspend) (struct pcmcia_socket *s); + int (*resume) (struct pcmcia_socket *s); }; int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); Index: 2.6.13-git4/drivers/pcmcia/ds.c =================================================================== --- 2.6.13-git4.orig/drivers/pcmcia/ds.c +++ 2.6.13-git4/drivers/pcmcia/ds.c @@ -915,6 +915,78 @@ static struct device_attribute pcmcia_de __ATTR_NULL, }; +/* PM support, also needed for reset */ + +static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) +{ + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + struct pcmcia_driver *p_drv = NULL; + + if (dev->driver) + p_drv = to_pcmcia_drv(dev->driver); + + if (p_drv && p_drv->suspend) + return p_drv->suspend(p_dev); + + return 0; +} + + +static int pcmcia_dev_resume(struct device * dev) +{ + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + struct pcmcia_driver *p_drv = NULL; + + if (dev->driver) + p_drv = to_pcmcia_drv(dev->driver); + + if (p_drv && p_drv->suspend) + return p_drv->suspend(p_dev); + + return 0; +} + + +static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) +{ + struct pcmcia_socket *skt = _data; + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + + if (p_dev->socket != skt) + return 0; + + return dpm_runtime_suspend(dev, PMSG_SUSPEND); +} + +static int pcmcia_bus_resume_callback(struct device *dev, void * _data) +{ + struct pcmcia_socket *skt = _data; + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + + if (p_dev->socket != skt) + return 0; + + dpm_runtime_resume(dev); + + return 0; +} + +static int pcmcia_bus_resume(struct pcmcia_socket *skt) +{ + bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); + return 0; +} + +static int pcmcia_bus_suspend(struct pcmcia_socket *skt) +{ + if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, + pcmcia_bus_suspend_callback)) { + pcmcia_bus_resume(skt); + return -EIO; + } + return 0; +} + /*====================================================================== @@ -922,6 +994,8 @@ static struct device_attribute pcmcia_de ======================================================================*/ + + struct send_event_data { struct pcmcia_socket *skt; event_t event; @@ -946,16 +1020,6 @@ static int send_event_callback(struct de if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) return 0; - if ((data->event == CS_EVENT_PM_SUSPEND) || - (data->event == CS_EVENT_RESET_PHYSICAL)) { - if (p_drv->suspend) - return p_drv->suspend(p_dev); - } else if ((data->event == CS_EVENT_PM_RESUME) || - (data->event == CS_EVENT_CARD_RESET)) { - if (p_drv->resume) - return p_drv->resume(p_dev); - } - if (p_drv->event) return p_drv->event(data->event, data->priority, &p_dev->event_callback_args); @@ -1007,6 +1071,13 @@ static int ds_event(struct pcmcia_socket ret = send_event(skt, event, priority); break; + case CS_EVENT_PM_SUSPEND: + case CS_EVENT_PM_RESUME: + case CS_EVENT_RESET_PHYSICAL: + case CS_EVENT_CARD_RESET: + handle_event(skt, event); + break; + default: handle_event(skt, event); send_event(skt, event, priority); @@ -1161,10 +1232,13 @@ int pcmcia_deregister_client(struct pcmc } /* deregister_client */ EXPORT_SYMBOL(pcmcia_deregister_client); + static struct pcmcia_callback pcmcia_bus_callback = { .owner = THIS_MODULE, .event = ds_event, .requery = pcmcia_bus_rescan, + .suspend = pcmcia_bus_suspend, + .resume = pcmcia_bus_resume, }; static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev) @@ -1231,6 +1305,8 @@ struct bus_type pcmcia_bus_type = { .hotplug = pcmcia_bus_hotplug, .match = pcmcia_bus_match, .dev_attrs = pcmcia_dev_attrs, + .suspend = pcmcia_dev_suspend, + .resume = pcmcia_dev_resume, }; Index: 2.6.13-git4/drivers/base/power/power.h =================================================================== --- 2.6.13-git4.orig/drivers/base/power/power.h +++ 2.6.13-git4/drivers/base/power/power.h @@ -63,13 +63,6 @@ extern int resume_device(struct device * extern int suspend_device(struct device *, pm_message_t); -/* - * runtime.c - */ - -extern int dpm_runtime_suspend(struct device *, pm_message_t); -extern void dpm_runtime_resume(struct device *); - #else /* CONFIG_PM */ @@ -82,14 +75,4 @@ static inline void device_pm_remove(stru } -static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state) -{ - return 0; -} - -static inline void dpm_runtime_resume(struct device * dev) -{ - -} - #endif Index: 2.6.13-git4/include/linux/device.h =================================================================== --- 2.6.13-git4.orig/include/linux/device.h +++ 2.6.13-git4/include/linux/device.h @@ -431,4 +431,24 @@ extern void firmware_unregister(struct s MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) #define MODULE_ALIAS_CHARDEV_MAJOR(major) \ MODULE_ALIAS("char-major-" __stringify(major) "-*") + +#ifdef CONFIG_PM + +extern int dpm_runtime_suspend(struct device *, pm_message_t); +extern void dpm_runtime_resume(struct device *); + +#else + +static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state) +{ + return 0; +} + +static inline void dpm_runtime_resume(struct device * dev) +{ + +} + +#endif /* CONFIG_PM */ + #endif /* _DEVICE_H_ */ Index: 2.6.13-git4/drivers/base/power/runtime.c =================================================================== --- 2.6.13-git4.orig/drivers/base/power/runtime.c +++ 2.6.13-git4/drivers/base/power/runtime.c @@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * runtime_resume(dev); up(&dpm_sem); } +EXPORT_SYMBOL_GPL(dpm_runtime_resume); /** @@ -61,6 +62,7 @@ int dpm_runtime_suspend(struct device * up(&dpm_sem); return error; } +EXPORT_SYMBOL_GPL(dpm_runtime_suspend); /**