diff options
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index a802c65c3534..5223395b246a 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -920,6 +920,78 @@ static struct device_attribute pcmcia_dev_attrs[] = { | |||
920 | __ATTR_NULL, | 920 | __ATTR_NULL, |
921 | }; | 921 | }; |
922 | 922 | ||
923 | /* PM support, also needed for reset */ | ||
924 | |||
925 | static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) | ||
926 | { | ||
927 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
928 | struct pcmcia_driver *p_drv = NULL; | ||
929 | |||
930 | if (dev->driver) | ||
931 | p_drv = to_pcmcia_drv(dev->driver); | ||
932 | |||
933 | if (p_drv && p_drv->suspend) | ||
934 | return p_drv->suspend(p_dev); | ||
935 | |||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | |||
940 | static int pcmcia_dev_resume(struct device * dev) | ||
941 | { | ||
942 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
943 | struct pcmcia_driver *p_drv = NULL; | ||
944 | |||
945 | if (dev->driver) | ||
946 | p_drv = to_pcmcia_drv(dev->driver); | ||
947 | |||
948 | if (p_drv && p_drv->resume) | ||
949 | return p_drv->resume(p_dev); | ||
950 | |||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | |||
955 | static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) | ||
956 | { | ||
957 | struct pcmcia_socket *skt = _data; | ||
958 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
959 | |||
960 | if (p_dev->socket != skt) | ||
961 | return 0; | ||
962 | |||
963 | return dpm_runtime_suspend(dev, PMSG_SUSPEND); | ||
964 | } | ||
965 | |||
966 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) | ||
967 | { | ||
968 | struct pcmcia_socket *skt = _data; | ||
969 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
970 | |||
971 | if (p_dev->socket != skt) | ||
972 | return 0; | ||
973 | |||
974 | dpm_runtime_resume(dev); | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static int pcmcia_bus_resume(struct pcmcia_socket *skt) | ||
980 | { | ||
981 | bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); | ||
982 | return 0; | ||
983 | } | ||
984 | |||
985 | static int pcmcia_bus_suspend(struct pcmcia_socket *skt) | ||
986 | { | ||
987 | if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, | ||
988 | pcmcia_bus_suspend_callback)) { | ||
989 | pcmcia_bus_resume(skt); | ||
990 | return -EIO; | ||
991 | } | ||
992 | return 0; | ||
993 | } | ||
994 | |||
923 | 995 | ||
924 | /*====================================================================== | 996 | /*====================================================================== |
925 | 997 | ||
@@ -951,16 +1023,6 @@ static int send_event_callback(struct device *dev, void * _data) | |||
951 | if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) | 1023 | if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) |
952 | return 0; | 1024 | return 0; |
953 | 1025 | ||
954 | if ((data->event == CS_EVENT_PM_SUSPEND) || | ||
955 | (data->event == CS_EVENT_RESET_PHYSICAL)) { | ||
956 | if (p_drv->suspend) | ||
957 | return p_drv->suspend(p_dev); | ||
958 | } else if ((data->event == CS_EVENT_PM_RESUME) || | ||
959 | (data->event == CS_EVENT_CARD_RESET)) { | ||
960 | if (p_drv->resume) | ||
961 | return p_drv->resume(p_dev); | ||
962 | } | ||
963 | |||
964 | if (p_drv->event) | 1026 | if (p_drv->event) |
965 | return p_drv->event(data->event, data->priority, | 1027 | return p_drv->event(data->event, data->priority, |
966 | &p_dev->event_callback_args); | 1028 | &p_dev->event_callback_args); |
@@ -1012,6 +1074,13 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1012 | ret = send_event(skt, event, priority); | 1074 | ret = send_event(skt, event, priority); |
1013 | break; | 1075 | break; |
1014 | 1076 | ||
1077 | case CS_EVENT_PM_SUSPEND: | ||
1078 | case CS_EVENT_PM_RESUME: | ||
1079 | case CS_EVENT_RESET_PHYSICAL: | ||
1080 | case CS_EVENT_CARD_RESET: | ||
1081 | handle_event(skt, event); | ||
1082 | break; | ||
1083 | |||
1015 | default: | 1084 | default: |
1016 | handle_event(skt, event); | 1085 | handle_event(skt, event); |
1017 | send_event(skt, event, priority); | 1086 | send_event(skt, event, priority); |
@@ -1166,10 +1235,13 @@ int pcmcia_deregister_client(struct pcmcia_device *p_dev) | |||
1166 | } /* deregister_client */ | 1235 | } /* deregister_client */ |
1167 | EXPORT_SYMBOL(pcmcia_deregister_client); | 1236 | EXPORT_SYMBOL(pcmcia_deregister_client); |
1168 | 1237 | ||
1238 | |||
1169 | static struct pcmcia_callback pcmcia_bus_callback = { | 1239 | static struct pcmcia_callback pcmcia_bus_callback = { |
1170 | .owner = THIS_MODULE, | 1240 | .owner = THIS_MODULE, |
1171 | .event = ds_event, | 1241 | .event = ds_event, |
1172 | .requery = pcmcia_bus_rescan, | 1242 | .requery = pcmcia_bus_rescan, |
1243 | .suspend = pcmcia_bus_suspend, | ||
1244 | .resume = pcmcia_bus_resume, | ||
1173 | }; | 1245 | }; |
1174 | 1246 | ||
1175 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, | 1247 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, |
@@ -1238,6 +1310,8 @@ struct bus_type pcmcia_bus_type = { | |||
1238 | .uevent = pcmcia_bus_uevent, | 1310 | .uevent = pcmcia_bus_uevent, |
1239 | .match = pcmcia_bus_match, | 1311 | .match = pcmcia_bus_match, |
1240 | .dev_attrs = pcmcia_dev_attrs, | 1312 | .dev_attrs = pcmcia_dev_attrs, |
1313 | .suspend = pcmcia_dev_suspend, | ||
1314 | .resume = pcmcia_dev_resume, | ||
1241 | }; | 1315 | }; |
1242 | 1316 | ||
1243 | 1317 | ||