[PATCH 7/13] pcmcia: use runtime suspend/resume support to unify all suspend code paths

Dominik Brodowski linux at dominikbrodowski.net
Wed Sep 7 17:37:27 EDT 2005


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 <linux at dominikbrodowski.net>
---
 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);
 
 
 /**



More information about the linux-pcmcia mailing list