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 e679e708db63..75ed866e6953 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c | |||
| @@ -76,65 +76,6 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem); | |||
| 76 | EXPORT_SYMBOL(pcmcia_socket_list_rwsem); | 76 | EXPORT_SYMBOL(pcmcia_socket_list_rwsem); |
| 77 | 77 | ||
| 78 | 78 | ||
| 79 | /* | ||
| 80 | * Low-level PCMCIA socket drivers need to register with the PCCard | ||
| 81 | * core using pcmcia_register_socket. | ||
| 82 | * | ||
| 83 | * socket drivers are expected to use the following callbacks in their | ||
| 84 | * .drv struct: | ||
| 85 | * - pcmcia_socket_dev_suspend | ||
| 86 | * - pcmcia_socket_dev_resume | ||
| 87 | * These functions check for the appropriate struct pcmcia_soket arrays, | ||
| 88 | * and pass them to the low-level functions pcmcia_{suspend,resume}_socket | ||
| 89 | */ | ||
| 90 | static int socket_early_resume(struct pcmcia_socket *skt); | ||
| 91 | static int socket_late_resume(struct pcmcia_socket *skt); | ||
| 92 | static int socket_resume(struct pcmcia_socket *skt); | ||
| 93 | static int socket_suspend(struct pcmcia_socket *skt); | ||
| 94 | |||
| 95 | static void pcmcia_socket_dev_run(struct device *dev, | ||
| 96 | int (*cb)(struct pcmcia_socket *)) | ||
| 97 | { | ||
| 98 | struct pcmcia_socket *socket; | ||
| 99 | |||
| 100 | down_read(&pcmcia_socket_list_rwsem); | ||
| 101 | list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { | ||
| 102 | if (socket->dev.parent != dev) | ||
| 103 | continue; | ||
| 104 | mutex_lock(&socket->skt_mutex); | ||
| 105 | cb(socket); | ||
| 106 | mutex_unlock(&socket->skt_mutex); | ||
| 107 | } | ||
| 108 | up_read(&pcmcia_socket_list_rwsem); | ||
| 109 | } | ||
| 110 | |||
| 111 | int pcmcia_socket_dev_suspend(struct device *dev) | ||
| 112 | { | ||
| 113 | pcmcia_socket_dev_run(dev, socket_suspend); | ||
| 114 | return 0; | ||
| 115 | } | ||
| 116 | EXPORT_SYMBOL(pcmcia_socket_dev_suspend); | ||
| 117 | |||
| 118 | void pcmcia_socket_dev_early_resume(struct device *dev) | ||
| 119 | { | ||
| 120 | pcmcia_socket_dev_run(dev, socket_early_resume); | ||
| 121 | } | ||
| 122 | EXPORT_SYMBOL(pcmcia_socket_dev_early_resume); | ||
| 123 | |||
| 124 | void pcmcia_socket_dev_late_resume(struct device *dev) | ||
| 125 | { | ||
| 126 | pcmcia_socket_dev_run(dev, socket_late_resume); | ||
| 127 | } | ||
| 128 | EXPORT_SYMBOL(pcmcia_socket_dev_late_resume); | ||
| 129 | |||
| 130 | int pcmcia_socket_dev_resume(struct device *dev) | ||
| 131 | { | ||
| 132 | pcmcia_socket_dev_run(dev, socket_resume); | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | EXPORT_SYMBOL(pcmcia_socket_dev_resume); | ||
| 136 | |||
| 137 | |||
| 138 | struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) | 79 | struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) |
| 139 | { | 80 | { |
| 140 | struct device *dev = get_device(&skt->dev); | 81 | struct device *dev = get_device(&skt->dev); |
| @@ -578,12 +519,18 @@ static int socket_early_resume(struct pcmcia_socket *skt) | |||
| 578 | 519 | ||
| 579 | static int socket_late_resume(struct pcmcia_socket *skt) | 520 | static int socket_late_resume(struct pcmcia_socket *skt) |
| 580 | { | 521 | { |
| 522 | int ret; | ||
| 523 | |||
| 581 | mutex_lock(&skt->ops_mutex); | 524 | mutex_lock(&skt->ops_mutex); |
| 582 | skt->state &= ~SOCKET_SUSPEND; | 525 | skt->state &= ~SOCKET_SUSPEND; |
| 583 | mutex_unlock(&skt->ops_mutex); | 526 | mutex_unlock(&skt->ops_mutex); |
| 584 | 527 | ||
| 585 | if (!(skt->state & SOCKET_PRESENT)) | 528 | if (!(skt->state & SOCKET_PRESENT)) { |
| 586 | return socket_insert(skt); | 529 | ret = socket_insert(skt); |
| 530 | if (ret == -ENODEV) | ||
| 531 | ret = 0; | ||
| 532 | return ret; | ||
| 533 | } | ||
| 587 | 534 | ||
| 588 | if (skt->resume_status) { | 535 | if (skt->resume_status) { |
| 589 | socket_shutdown(skt); | 536 | socket_shutdown(skt); |
| @@ -919,11 +866,66 @@ static void pcmcia_release_socket_class(struct class *data) | |||
| 919 | } | 866 | } |
| 920 | 867 | ||
| 921 | 868 | ||
| 869 | #ifdef CONFIG_PM | ||
| 870 | |||
| 871 | static int __pcmcia_pm_op(struct device *dev, | ||
| 872 | int (*callback) (struct pcmcia_socket *skt)) | ||
| 873 | { | ||
| 874 | struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); | ||
| 875 | int ret; | ||
| 876 | |||
| 877 | mutex_lock(&s->skt_mutex); | ||
| 878 | ret = callback(s); | ||
| 879 | mutex_unlock(&s->skt_mutex); | ||
| 880 | |||
| 881 | return ret; | ||
| 882 | } | ||
| 883 | |||
| 884 | static int pcmcia_socket_dev_suspend_noirq(struct device *dev) | ||
| 885 | { | ||
| 886 | return __pcmcia_pm_op(dev, socket_suspend); | ||
| 887 | } | ||
| 888 | |||
| 889 | static int pcmcia_socket_dev_resume_noirq(struct device *dev) | ||
| 890 | { | ||
| 891 | return __pcmcia_pm_op(dev, socket_early_resume); | ||
| 892 | } | ||
| 893 | |||
| 894 | static int pcmcia_socket_dev_resume(struct device *dev) | ||
| 895 | { | ||
| 896 | return __pcmcia_pm_op(dev, socket_late_resume); | ||
| 897 | } | ||
| 898 | |||
| 899 | static const struct dev_pm_ops pcmcia_socket_pm_ops = { | ||
| 900 | /* dev_resume may be called with IRQs enabled */ | ||
| 901 | SET_SYSTEM_SLEEP_PM_OPS(NULL, | ||
| 902 | pcmcia_socket_dev_resume) | ||
| 903 | |||
| 904 | /* late suspend must be called with IRQs disabled */ | ||
| 905 | .suspend_noirq = pcmcia_socket_dev_suspend_noirq, | ||
| 906 | .freeze_noirq = pcmcia_socket_dev_suspend_noirq, | ||
| 907 | .poweroff_noirq = pcmcia_socket_dev_suspend_noirq, | ||
| 908 | |||
| 909 | /* early resume must be called with IRQs disabled */ | ||
| 910 | .resume_noirq = pcmcia_socket_dev_resume_noirq, | ||
| 911 | .thaw_noirq = pcmcia_socket_dev_resume_noirq, | ||
| 912 | .restore_noirq = pcmcia_socket_dev_resume_noirq, | ||
| 913 | }; | ||
| 914 | |||
| 915 | #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) | ||
| 916 | |||
| 917 | #else /* CONFIG_PM */ | ||
| 918 | |||
| 919 | #define PCMCIA_SOCKET_CLASS_PM_OPS NULL | ||
| 920 | |||
| 921 | #endif /* CONFIG_PM */ | ||
| 922 | |||
| 922 | struct class pcmcia_socket_class = { | 923 | struct class pcmcia_socket_class = { |
| 923 | .name = "pcmcia_socket", | 924 | .name = "pcmcia_socket", |
| 924 | .dev_uevent = pcmcia_socket_uevent, | 925 | .dev_uevent = pcmcia_socket_uevent, |
| 925 | .dev_release = pcmcia_release_socket, | 926 | .dev_release = pcmcia_release_socket, |
| 926 | .class_release = pcmcia_release_socket_class, | 927 | .class_release = pcmcia_release_socket_class, |
| 928 | .pm = PCMCIA_SOCKET_CLASS_PM_OPS, | ||
| 927 | }; | 929 | }; |
| 928 | EXPORT_SYMBOL(pcmcia_socket_class); | 930 | EXPORT_SYMBOL(pcmcia_socket_class); |
| 929 | 931 | ||
