]> git.karo-electronics.de Git - mv-sheeva.git/blob - kernel/power/user.c
Hibernation: Correct definitions of some ioctls (rev. 2)
[mv-sheeva.git] / kernel / power / user.c
1 /*
2  * linux/kernel/power/user.c
3  *
4  * This file provides the user space interface for software suspend/resume.
5  *
6  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
7  *
8  * This file is released under the GPLv2.
9  *
10  */
11
12 #include <linux/suspend.h>
13 #include <linux/syscalls.h>
14 #include <linux/reboot.h>
15 #include <linux/string.h>
16 #include <linux/device.h>
17 #include <linux/miscdevice.h>
18 #include <linux/mm.h>
19 #include <linux/swap.h>
20 #include <linux/swapops.h>
21 #include <linux/pm.h>
22 #include <linux/fs.h>
23 #include <linux/console.h>
24 #include <linux/cpu.h>
25 #include <linux/freezer.h>
26
27 #include <asm/uaccess.h>
28
29 #include "power.h"
30
31 /*
32  * NOTE: The SNAPSHOT_SET_SWAP_FILE and SNAPSHOT_PMOPS ioctls are obsolete and
33  * will be removed in the future.  They are only preserved here for
34  * compatibility with existing userland utilities.
35  */
36 #define SNAPSHOT_SET_SWAP_FILE  _IOW(SNAPSHOT_IOC_MAGIC, 10, unsigned int)
37 #define SNAPSHOT_PMOPS          _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int)
38
39 #define PMOPS_PREPARE   1
40 #define PMOPS_ENTER     2
41 #define PMOPS_FINISH    3
42
43 /*
44  * NOTE: The following ioctl definitions are wrong and have been replaced with
45  * correct ones.  They are only preserved here for compatibility with existing
46  * userland utilities and will be removed in the future.
47  */
48 #define SNAPSHOT_ATOMIC_SNAPSHOT        _IOW(SNAPSHOT_IOC_MAGIC, 3, void *)
49 #define SNAPSHOT_SET_IMAGE_SIZE         _IOW(SNAPSHOT_IOC_MAGIC, 6, unsigned long)
50 #define SNAPSHOT_AVAIL_SWAP             _IOR(SNAPSHOT_IOC_MAGIC, 7, void *)
51 #define SNAPSHOT_GET_SWAP_PAGE          _IOR(SNAPSHOT_IOC_MAGIC, 8, void *)
52
53
54 #define SNAPSHOT_MINOR  231
55
56 static struct snapshot_data {
57         struct snapshot_handle handle;
58         int swap;
59         int mode;
60         char frozen;
61         char ready;
62         char platform_support;
63 } snapshot_state;
64
65 atomic_t snapshot_device_available = ATOMIC_INIT(1);
66
67 static int snapshot_open(struct inode *inode, struct file *filp)
68 {
69         struct snapshot_data *data;
70
71         if (!atomic_add_unless(&snapshot_device_available, -1, 0))
72                 return -EBUSY;
73
74         if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
75                 atomic_inc(&snapshot_device_available);
76                 return -ENOSYS;
77         }
78         if(create_basic_memory_bitmaps()) {
79                 atomic_inc(&snapshot_device_available);
80                 return -ENOMEM;
81         }
82         nonseekable_open(inode, filp);
83         data = &snapshot_state;
84         filp->private_data = data;
85         memset(&data->handle, 0, sizeof(struct snapshot_handle));
86         if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
87                 data->swap = swsusp_resume_device ?
88                         swap_type_of(swsusp_resume_device, 0, NULL) : -1;
89                 data->mode = O_RDONLY;
90         } else {
91                 data->swap = -1;
92                 data->mode = O_WRONLY;
93         }
94         data->frozen = 0;
95         data->ready = 0;
96         data->platform_support = 0;
97
98         return 0;
99 }
100
101 static int snapshot_release(struct inode *inode, struct file *filp)
102 {
103         struct snapshot_data *data;
104
105         swsusp_free();
106         free_basic_memory_bitmaps();
107         data = filp->private_data;
108         free_all_swap_pages(data->swap);
109         if (data->frozen) {
110                 mutex_lock(&pm_mutex);
111                 thaw_processes();
112                 mutex_unlock(&pm_mutex);
113         }
114         atomic_inc(&snapshot_device_available);
115         return 0;
116 }
117
118 static ssize_t snapshot_read(struct file *filp, char __user *buf,
119                              size_t count, loff_t *offp)
120 {
121         struct snapshot_data *data;
122         ssize_t res;
123
124         data = filp->private_data;
125         if (!data->ready)
126                 return -ENODATA;
127         res = snapshot_read_next(&data->handle, count);
128         if (res > 0) {
129                 if (copy_to_user(buf, data_of(data->handle), res))
130                         res = -EFAULT;
131                 else
132                         *offp = data->handle.offset;
133         }
134         return res;
135 }
136
137 static ssize_t snapshot_write(struct file *filp, const char __user *buf,
138                               size_t count, loff_t *offp)
139 {
140         struct snapshot_data *data;
141         ssize_t res;
142
143         data = filp->private_data;
144         res = snapshot_write_next(&data->handle, count);
145         if (res > 0) {
146                 if (copy_from_user(data_of(data->handle), buf, res))
147                         res = -EFAULT;
148                 else
149                         *offp = data->handle.offset;
150         }
151         return res;
152 }
153
154 static int snapshot_ioctl(struct inode *inode, struct file *filp,
155                           unsigned int cmd, unsigned long arg)
156 {
157         int error = 0;
158         struct snapshot_data *data;
159         loff_t size;
160         sector_t offset;
161
162         if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
163                 return -ENOTTY;
164         if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
165                 return -ENOTTY;
166         if (!capable(CAP_SYS_ADMIN))
167                 return -EPERM;
168
169         data = filp->private_data;
170
171         switch (cmd) {
172
173         case SNAPSHOT_FREEZE:
174                 if (data->frozen)
175                         break;
176                 mutex_lock(&pm_mutex);
177                 error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
178                 if (!error) {
179                         printk("Syncing filesystems ... ");
180                         sys_sync();
181                         printk("done.\n");
182
183                         error = freeze_processes();
184                         if (error)
185                                 thaw_processes();
186                 }
187                 if (error)
188                         pm_notifier_call_chain(PM_POST_HIBERNATION);
189                 mutex_unlock(&pm_mutex);
190                 if (!error)
191                         data->frozen = 1;
192                 break;
193
194         case SNAPSHOT_UNFREEZE:
195                 if (!data->frozen || data->ready)
196                         break;
197                 mutex_lock(&pm_mutex);
198                 thaw_processes();
199                 pm_notifier_call_chain(PM_POST_HIBERNATION);
200                 mutex_unlock(&pm_mutex);
201                 data->frozen = 0;
202                 break;
203
204         case SNAPSHOT_CREATE_IMAGE:
205         case SNAPSHOT_ATOMIC_SNAPSHOT:
206                 if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
207                         error = -EPERM;
208                         break;
209                 }
210                 error = hibernation_snapshot(data->platform_support);
211                 if (!error)
212                         error = put_user(in_suspend, (int __user *)arg);
213                 if (!error)
214                         data->ready = 1;
215                 break;
216
217         case SNAPSHOT_ATOMIC_RESTORE:
218                 snapshot_write_finalize(&data->handle);
219                 if (data->mode != O_WRONLY || !data->frozen ||
220                     !snapshot_image_loaded(&data->handle)) {
221                         error = -EPERM;
222                         break;
223                 }
224                 error = hibernation_restore(data->platform_support);
225                 break;
226
227         case SNAPSHOT_FREE:
228                 swsusp_free();
229                 memset(&data->handle, 0, sizeof(struct snapshot_handle));
230                 data->ready = 0;
231                 break;
232
233         case SNAPSHOT_PREF_IMAGE_SIZE:
234         case SNAPSHOT_SET_IMAGE_SIZE:
235                 image_size = arg;
236                 break;
237
238         case SNAPSHOT_GET_IMAGE_SIZE:
239                 if (!data->ready) {
240                         error = -ENODATA;
241                         break;
242                 }
243                 size = snapshot_get_image_size();
244                 size <<= PAGE_SHIFT;
245                 error = put_user(size, (loff_t __user *)arg);
246                 break;
247
248         case SNAPSHOT_AVAIL_SWAP_SIZE:
249         case SNAPSHOT_AVAIL_SWAP:
250                 size = count_swap_pages(data->swap, 1);
251                 size <<= PAGE_SHIFT;
252                 error = put_user(size, (loff_t __user *)arg);
253                 break;
254
255         case SNAPSHOT_ALLOC_SWAP_PAGE:
256         case SNAPSHOT_GET_SWAP_PAGE:
257                 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
258                         error = -ENODEV;
259                         break;
260                 }
261                 offset = alloc_swapdev_block(data->swap);
262                 if (offset) {
263                         offset <<= PAGE_SHIFT;
264                         error = put_user(offset, (loff_t __user *)arg);
265                 } else {
266                         error = -ENOSPC;
267                 }
268                 break;
269
270         case SNAPSHOT_FREE_SWAP_PAGES:
271                 if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
272                         error = -ENODEV;
273                         break;
274                 }
275                 free_all_swap_pages(data->swap);
276                 break;
277
278         case SNAPSHOT_SET_SWAP_FILE: /* This ioctl is deprecated */
279                 if (!swsusp_swap_in_use()) {
280                         /*
281                          * User space encodes device types as two-byte values,
282                          * so we need to recode them
283                          */
284                         if (old_decode_dev(arg)) {
285                                 data->swap = swap_type_of(old_decode_dev(arg),
286                                                         0, NULL);
287                                 if (data->swap < 0)
288                                         error = -ENODEV;
289                         } else {
290                                 data->swap = -1;
291                                 error = -EINVAL;
292                         }
293                 } else {
294                         error = -EPERM;
295                 }
296                 break;
297
298         case SNAPSHOT_S2RAM:
299                 if (!data->frozen) {
300                         error = -EPERM;
301                         break;
302                 }
303                 if (!mutex_trylock(&pm_mutex)) {
304                         error = -EBUSY;
305                         break;
306                 }
307                 /*
308                  * Tasks are frozen and the notifiers have been called with
309                  * PM_HIBERNATION_PREPARE
310                  */
311                 error = suspend_devices_and_enter(PM_SUSPEND_MEM);
312                 mutex_unlock(&pm_mutex);
313                 break;
314
315         case SNAPSHOT_PLATFORM_SUPPORT:
316                 data->platform_support = !!arg;
317                 break;
318
319         case SNAPSHOT_POWER_OFF:
320                 if (data->platform_support)
321                         error = hibernation_platform_enter();
322                 break;
323
324         case SNAPSHOT_PMOPS: /* This ioctl is deprecated */
325                 error = -EINVAL;
326
327                 switch (arg) {
328
329                 case PMOPS_PREPARE:
330                         data->platform_support = 1;
331                         error = 0;
332                         break;
333
334                 case PMOPS_ENTER:
335                         if (data->platform_support)
336                                 error = hibernation_platform_enter();
337                         break;
338
339                 case PMOPS_FINISH:
340                         if (data->platform_support)
341                                 error = 0;
342                         break;
343
344                 default:
345                         printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
346
347                 }
348                 break;
349
350         case SNAPSHOT_SET_SWAP_AREA:
351                 if (swsusp_swap_in_use()) {
352                         error = -EPERM;
353                 } else {
354                         struct resume_swap_area swap_area;
355                         dev_t swdev;
356
357                         error = copy_from_user(&swap_area, (void __user *)arg,
358                                         sizeof(struct resume_swap_area));
359                         if (error) {
360                                 error = -EFAULT;
361                                 break;
362                         }
363
364                         /*
365                          * User space encodes device types as two-byte values,
366                          * so we need to recode them
367                          */
368                         swdev = old_decode_dev(swap_area.dev);
369                         if (swdev) {
370                                 offset = swap_area.offset;
371                                 data->swap = swap_type_of(swdev, offset, NULL);
372                                 if (data->swap < 0)
373                                         error = -ENODEV;
374                         } else {
375                                 data->swap = -1;
376                                 error = -EINVAL;
377                         }
378                 }
379                 break;
380
381         default:
382                 error = -ENOTTY;
383
384         }
385
386         return error;
387 }
388
389 static const struct file_operations snapshot_fops = {
390         .open = snapshot_open,
391         .release = snapshot_release,
392         .read = snapshot_read,
393         .write = snapshot_write,
394         .llseek = no_llseek,
395         .ioctl = snapshot_ioctl,
396 };
397
398 static struct miscdevice snapshot_device = {
399         .minor = SNAPSHOT_MINOR,
400         .name = "snapshot",
401         .fops = &snapshot_fops,
402 };
403
404 static int __init snapshot_device_init(void)
405 {
406         return misc_register(&snapshot_device);
407 };
408
409 device_initcall(snapshot_device_init);