diff options
Diffstat (limited to 'drivers/pcmcia/cs.c')
| -rw-r--r-- | drivers/pcmcia/cs.c | 124 | 
1 files changed, 63 insertions, 61 deletions
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e679e708db6..75ed866e695 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -76,65 +76,6 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem);  EXPORT_SYMBOL(pcmcia_socket_list_rwsem); -/* - * Low-level PCMCIA socket drivers need to register with the PCCard - * core using pcmcia_register_socket. - * - * socket drivers are expected to use the following callbacks in their - * .drv struct: - *  - pcmcia_socket_dev_suspend - *  - pcmcia_socket_dev_resume - * These functions check for the appropriate struct pcmcia_soket arrays, - * and pass them to the low-level functions pcmcia_{suspend,resume}_socket - */ -static int socket_early_resume(struct pcmcia_socket *skt); -static int socket_late_resume(struct pcmcia_socket *skt); -static int socket_resume(struct pcmcia_socket *skt); -static int socket_suspend(struct pcmcia_socket *skt); - -static void pcmcia_socket_dev_run(struct device *dev, -				  int (*cb)(struct pcmcia_socket *)) -{ -	struct pcmcia_socket *socket; - -	down_read(&pcmcia_socket_list_rwsem); -	list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { -		if (socket->dev.parent != dev) -			continue; -		mutex_lock(&socket->skt_mutex); -		cb(socket); -		mutex_unlock(&socket->skt_mutex); -	} -	up_read(&pcmcia_socket_list_rwsem); -} - -int pcmcia_socket_dev_suspend(struct device *dev) -{ -	pcmcia_socket_dev_run(dev, socket_suspend); -	return 0; -} -EXPORT_SYMBOL(pcmcia_socket_dev_suspend); - -void pcmcia_socket_dev_early_resume(struct device *dev) -{ -	pcmcia_socket_dev_run(dev, socket_early_resume); -} -EXPORT_SYMBOL(pcmcia_socket_dev_early_resume); - -void pcmcia_socket_dev_late_resume(struct device *dev) -{ -	pcmcia_socket_dev_run(dev, socket_late_resume); -} -EXPORT_SYMBOL(pcmcia_socket_dev_late_resume); - -int pcmcia_socket_dev_resume(struct device *dev) -{ -	pcmcia_socket_dev_run(dev, socket_resume); -	return 0; -} -EXPORT_SYMBOL(pcmcia_socket_dev_resume); - -  struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt)  {  	struct device *dev = get_device(&skt->dev); @@ -578,12 +519,18 @@ static int socket_early_resume(struct pcmcia_socket *skt)  static int socket_late_resume(struct pcmcia_socket *skt)  { +	int ret; +  	mutex_lock(&skt->ops_mutex);  	skt->state &= ~SOCKET_SUSPEND;  	mutex_unlock(&skt->ops_mutex); -	if (!(skt->state & SOCKET_PRESENT)) -		return socket_insert(skt); +	if (!(skt->state & SOCKET_PRESENT)) { +		ret = socket_insert(skt); +		if (ret == -ENODEV) +			ret = 0; +		return ret; +	}  	if (skt->resume_status) {  		socket_shutdown(skt); @@ -919,11 +866,66 @@ static void pcmcia_release_socket_class(struct class *data)  } +#ifdef CONFIG_PM + +static int __pcmcia_pm_op(struct device *dev, +			  int (*callback) (struct pcmcia_socket *skt)) +{ +	struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); +	int ret; + +	mutex_lock(&s->skt_mutex); +	ret = callback(s); +	mutex_unlock(&s->skt_mutex); + +	return ret; +} + +static int pcmcia_socket_dev_suspend_noirq(struct device *dev) +{ +	return __pcmcia_pm_op(dev, socket_suspend); +} + +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) +{ +	return __pcmcia_pm_op(dev, socket_late_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, +				pcmcia_socket_dev_resume) + +	/* late suspend must be called with IRQs disabled */ +	.suspend_noirq = pcmcia_socket_dev_suspend_noirq, +	.freeze_noirq = pcmcia_socket_dev_suspend_noirq, +	.poweroff_noirq = pcmcia_socket_dev_suspend_noirq, + +	/* early resume must be called with IRQs disabled */ +	.resume_noirq = pcmcia_socket_dev_resume_noirq, +	.thaw_noirq = pcmcia_socket_dev_resume_noirq, +	.restore_noirq = pcmcia_socket_dev_resume_noirq, +}; + +#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) + +#else /* CONFIG_PM */ + +#define PCMCIA_SOCKET_CLASS_PM_OPS NULL + +#endif /* CONFIG_PM */ +  struct class pcmcia_socket_class = {  	.name = "pcmcia_socket",  	.dev_uevent = pcmcia_socket_uevent,  	.dev_release = pcmcia_release_socket,  	.class_release = pcmcia_release_socket_class, +	.pm = PCMCIA_SOCKET_CLASS_PM_OPS,  };  EXPORT_SYMBOL(pcmcia_socket_class);  |