diff options
| -rw-r--r-- | drivers/s390/net/smsgiucv.c | 63 |
1 files changed, 60 insertions, 3 deletions
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090c2625..e76a320d373b 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * IUCV special message driver | 2 | * IUCV special message driver |
| 3 | * | 3 | * |
| 4 | * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2003, 2009 |
| 5 | * | ||
| 5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
| 6 | * | 7 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| @@ -40,6 +41,8 @@ MODULE_AUTHOR | |||
| 40 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); | 41 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); |
| 41 | 42 | ||
| 42 | static struct iucv_path *smsg_path; | 43 | static struct iucv_path *smsg_path; |
| 44 | /* dummy device used as trigger for PM functions */ | ||
| 45 | static struct device *smsg_dev; | ||
| 43 | 46 | ||
| 44 | static DEFINE_SPINLOCK(smsg_list_lock); | 47 | static DEFINE_SPINLOCK(smsg_list_lock); |
| 45 | static LIST_HEAD(smsg_list); | 48 | static LIST_HEAD(smsg_list); |
| @@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix, | |||
| 132 | kfree(cb); | 135 | kfree(cb); |
| 133 | } | 136 | } |
| 134 | 137 | ||
| 138 | static int smsg_pm_freeze(struct device *dev) | ||
| 139 | { | ||
| 140 | #ifdef CONFIG_PM_DEBUG | ||
| 141 | printk(KERN_WARNING "smsg_pm_freeze\n"); | ||
| 142 | #endif | ||
| 143 | if (smsg_path) | ||
| 144 | iucv_path_sever(smsg_path, NULL); | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static int smsg_pm_restore_thaw(struct device *dev) | ||
| 149 | { | ||
| 150 | int rc; | ||
| 151 | |||
| 152 | #ifdef CONFIG_PM_DEBUG | ||
| 153 | printk(KERN_WARNING "smsg_pm_restore_thaw\n"); | ||
| 154 | #endif | ||
| 155 | if (smsg_path) { | ||
| 156 | memset(smsg_path, 0, sizeof(*smsg_path)); | ||
| 157 | smsg_path->msglim = 255; | ||
| 158 | smsg_path->flags = 0; | ||
| 159 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | ||
| 160 | NULL, NULL, NULL); | ||
| 161 | printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc); | ||
| 162 | } | ||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | static struct dev_pm_ops smsg_pm_ops = { | ||
| 167 | .freeze = smsg_pm_freeze, | ||
| 168 | .thaw = smsg_pm_restore_thaw, | ||
| 169 | .restore = smsg_pm_restore_thaw, | ||
| 170 | }; | ||
| 171 | |||
| 135 | static struct device_driver smsg_driver = { | 172 | static struct device_driver smsg_driver = { |
| 173 | .owner = THIS_MODULE, | ||
| 136 | .name = "SMSGIUCV", | 174 | .name = "SMSGIUCV", |
| 137 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
| 176 | .pm = &smsg_pm_ops, | ||
| 138 | }; | 177 | }; |
| 139 | 178 | ||
| 140 | static void __exit smsg_exit(void) | 179 | static void __exit smsg_exit(void) |
| 141 | { | 180 | { |
| 142 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 181 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
| 182 | device_unregister(smsg_dev); | ||
| 143 | iucv_unregister(&smsg_handler, 1); | 183 | iucv_unregister(&smsg_handler, 1); |
| 144 | driver_unregister(&smsg_driver); | 184 | driver_unregister(&smsg_driver); |
| 145 | } | 185 | } |
| @@ -166,12 +206,29 @@ static int __init smsg_init(void) | |||
| 166 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | 206 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", |
| 167 | NULL, NULL, NULL); | 207 | NULL, NULL, NULL); |
| 168 | if (rc) | 208 | if (rc) |
| 169 | goto out_free; | 209 | goto out_free_path; |
| 210 | smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 211 | if (!smsg_dev) { | ||
| 212 | rc = -ENOMEM; | ||
| 213 | goto out_free_path; | ||
| 214 | } | ||
| 215 | dev_set_name(smsg_dev, "smsg_iucv"); | ||
| 216 | smsg_dev->bus = &iucv_bus; | ||
| 217 | smsg_dev->parent = iucv_root; | ||
| 218 | smsg_dev->release = (void (*)(struct device *))kfree; | ||
| 219 | smsg_dev->driver = &smsg_driver; | ||
| 220 | rc = device_register(smsg_dev); | ||
| 221 | if (rc) | ||
| 222 | goto out_free_dev; | ||
| 223 | |||
| 170 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 224 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
| 171 | return 0; | 225 | return 0; |
| 172 | 226 | ||
| 173 | out_free: | 227 | out_free_dev: |
| 228 | kfree(smsg_dev); | ||
| 229 | out_free_path: | ||
| 174 | iucv_path_free(smsg_path); | 230 | iucv_path_free(smsg_path); |
| 231 | smsg_path = NULL; | ||
| 175 | out_register: | 232 | out_register: |
| 176 | iucv_unregister(&smsg_handler, 1); | 233 | iucv_unregister(&smsg_handler, 1); |
| 177 | out_driver: | 234 | out_driver: |
