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#define SNAPSHOT_MINOR	231
32
33static struct snapshot_data {
34	struct snapshot_handle handle;
35	int swap;
36	int mode;
37	char frozen;
38	char ready;
39	char platform_suspend;
40} snapshot_state;
41
42atomic_t snapshot_device_available = ATOMIC_INIT(1);
43
44static int snapshot_open(struct inode *inode, struct file *filp)
45{
46	struct snapshot_data *data;
47
48	if (!atomic_add_unless(&snapshot_device_available, -1, 0))
49		return -EBUSY;
50
51	if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
52		atomic_inc(&snapshot_device_available);
53		return -ENOSYS;
54	}
55	if(create_basic_memory_bitmaps()) {
56		atomic_inc(&snapshot_device_available);
57		return -ENOMEM;
58	}
59	nonseekable_open(inode, filp);
60	data = &snapshot_state;
61	filp->private_data = data;
62	memset(&data->handle, 0, sizeof(struct snapshot_handle));
63	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
64		data->swap = swsusp_resume_device ?
65			swap_type_of(swsusp_resume_device, 0, NULL) : -1;
66		data->mode = O_RDONLY;
67	} else {
68		data->swap = -1;
69		data->mode = O_WRONLY;
70	}
71	data->frozen = 0;
72	data->ready = 0;
73	data->platform_suspend = 0;
74
75	return 0;
76}
77
78static int snapshot_release(struct inode *inode, struct file *filp)
79{
80	struct snapshot_data *data;
81
82	swsusp_free();
83	free_basic_memory_bitmaps();
84	data = filp->private_data;
85	free_all_swap_pages(data->swap);
86	if (data->frozen) {
87		mutex_lock(&pm_mutex);
88		thaw_processes();
89		mutex_unlock(&pm_mutex);
90	}
91	atomic_inc(&snapshot_device_available);
92	return 0;
93}
94
95static ssize_t snapshot_read(struct file *filp, char __user *buf,
96                             size_t count, loff_t *offp)
97{
98	struct snapshot_data *data;
99	ssize_t res;
100
101	data = filp->private_data;
102	if (!data->ready)
103		return -ENODATA;
104	res = snapshot_read_next(&data->handle, count);
105	if (res > 0) {
106		if (copy_to_user(buf, data_of(data->handle), res))
107			res = -EFAULT;
108		else
109			*offp = data->handle.offset;
110	}
111	return res;
112}
113
114static ssize_t snapshot_write(struct file *filp, const char __user *buf,
115                              size_t count, loff_t *offp)
116{
117	struct snapshot_data *data;
118	ssize_t res;
119
120	data = filp->private_data;
121	res = snapshot_write_next(&data->handle, count);
122	if (res > 0) {
123		if (copy_from_user(data_of(data->handle), buf, res))
124			res = -EFAULT;
125		else
126			*offp = data->handle.offset;
127	}
128	return res;
129}
130
131static inline int platform_prepare(void)
132{
133	int error = 0;
134
135	if (hibernation_ops)
136		error = hibernation_ops->prepare();
137
138	return error;
139}
140
141static inline void platform_finish(void)
142{
143	if (hibernation_ops)
144		hibernation_ops->finish();
145}
146
147static inline int snapshot_suspend(int platform_suspend)
148{
149	int error;
150
151	mutex_lock(&pm_mutex);
152	/* Free memory before shutting down devices. */
153	error = swsusp_shrink_memory();
154	if (error)
155		goto Finish;
156
157	if (platform_suspend) {
158		error = platform_prepare();
159		if (error)
160			goto Finish;
161	}
162	suspend_console();
163	error = device_suspend(PMSG_FREEZE);
164	if (error)
165		goto Resume_devices;
166
167	error = disable_nonboot_cpus();
168	if (!error) {
169		in_suspend = 1;
170		error = swsusp_suspend();
171	}
172	enable_nonboot_cpus();
173 Resume_devices:
174	if (platform_suspend)
175		platform_finish();
176
177	device_resume();
178	resume_console();
179 Finish:
180	mutex_unlock(&pm_mutex);
181	return error;
182}
183
184static inline int snapshot_restore(int platform_suspend)
185{
186	int error;
187
188	mutex_lock(&pm_mutex);
189	pm_prepare_console();
190	if (platform_suspend) {
191		error = platform_prepare();
192		if (error)
193			goto Finish;
194	}
195	suspend_console();
196	error = device_suspend(PMSG_PRETHAW);
197	if (error)
198		goto Resume_devices;
199
200	error = disable_nonboot_cpus();
201	if (!error)
202		error = swsusp_resume();
203
204	enable_nonboot_cpus();
205 Resume_devices:
206	if (platform_suspend)
207		platform_finish();
208
209	device_resume();
210	resume_console();
211 Finish:
212	pm_restore_console();
213	mutex_unlock(&pm_mutex);
214	return error;
215}
216
217static int snapshot_ioctl(struct inode *inode, struct file *filp,
218                          unsigned int cmd, unsigned long arg)
219{
220	int error = 0;
221	struct snapshot_data *data;
222	loff_t avail;
223	sector_t offset;
224
225	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
226		return -ENOTTY;
227	if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
228		return -ENOTTY;
229	if (!capable(CAP_SYS_ADMIN))
230		return -EPERM;
231
232	data = filp->private_data;
233
234	switch (cmd) {
235
236	case SNAPSHOT_FREEZE:
237		if (data->frozen)
238			break;
239		mutex_lock(&pm_mutex);
240		if (freeze_processes()) {
241			thaw_processes();
242			error = -EBUSY;
243		}
244		mutex_unlock(&pm_mutex);
245		if (!error)
246			data->frozen = 1;
247		break;
248
249	case SNAPSHOT_UNFREEZE:
250		if (!data->frozen || data->ready)
251			break;
252		mutex_lock(&pm_mutex);
253		thaw_processes();
254		mutex_unlock(&pm_mutex);
255		data->frozen = 0;
256		break;
257
258	case SNAPSHOT_ATOMIC_SNAPSHOT:
259		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
260			error = -EPERM;
261			break;
262		}
263		error = snapshot_suspend(data->platform_suspend);
264		if (!error)
265			error = put_user(in_suspend, (unsigned int __user *)arg);
266		if (!error)
267			data->ready = 1;
268		break;
269
270	case SNAPSHOT_ATOMIC_RESTORE:
271		snapshot_write_finalize(&data->handle);
272		if (data->mode != O_WRONLY || !data->frozen ||
273		    !snapshot_image_loaded(&data->handle)) {
274			error = -EPERM;
275			break;
276		}
277		error = snapshot_restore(data->platform_suspend);
278		break;
279
280	case SNAPSHOT_FREE:
281		swsusp_free();
282		memset(&data->handle, 0, sizeof(struct snapshot_handle));
283		data->ready = 0;
284		break;
285
286	case SNAPSHOT_SET_IMAGE_SIZE:
287		image_size = arg;
288		break;
289
290	case SNAPSHOT_AVAIL_SWAP:
291		avail = count_swap_pages(data->swap, 1);
292		avail <<= PAGE_SHIFT;
293		error = put_user(avail, (loff_t __user *)arg);
294		break;
295
296	case SNAPSHOT_GET_SWAP_PAGE:
297		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
298			error = -ENODEV;
299			break;
300		}
301		offset = alloc_swapdev_block(data->swap);
302		if (offset) {
303			offset <<= PAGE_SHIFT;
304			error = put_user(offset, (sector_t __user *)arg);
305		} else {
306			error = -ENOSPC;
307		}
308		break;
309
310	case SNAPSHOT_FREE_SWAP_PAGES:
311		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
312			error = -ENODEV;
313			break;
314		}
315		free_all_swap_pages(data->swap);
316		break;
317
318	case SNAPSHOT_SET_SWAP_FILE:
319		if (!swsusp_swap_in_use()) {
320			/*
321			 * User space encodes device types as two-byte values,
322			 * so we need to recode them
323			 */
324			if (old_decode_dev(arg)) {
325				data->swap = swap_type_of(old_decode_dev(arg),
326							0, NULL);
327				if (data->swap < 0)
328					error = -ENODEV;
329			} else {
330				data->swap = -1;
331				error = -EINVAL;
332			}
333		} else {
334			error = -EPERM;
335		}
336		break;
337
338	case SNAPSHOT_S2RAM:
339		if (!pm_ops) {
340			error = -ENOSYS;
341			break;
342		}
343
344		if (!data->frozen) {
345			error = -EPERM;
346			break;
347		}
348
349		if (!mutex_trylock(&pm_mutex)) {
350			error = -EBUSY;
351			break;
352		}
353
354		if (pm_ops->prepare) {
355			error = pm_ops->prepare(PM_SUSPEND_MEM);
356			if (error)
357				goto OutS3;
358		}
359
360		/* Put devices to sleep */
361		suspend_console();
362		error = device_suspend(PMSG_SUSPEND);
363		if (error) {
364			printk(KERN_ERR "Failed to suspend some devices.\n");
365		} else {
366			error = disable_nonboot_cpus();
367			if (!error) {
368				/* Enter S3, system is already frozen */
369				suspend_enter(PM_SUSPEND_MEM);
370				enable_nonboot_cpus();
371			}
372			/* Wake up devices */
373			device_resume();
374		}
375		resume_console();
376		if (pm_ops->finish)
377			pm_ops->finish(PM_SUSPEND_MEM);
378
379 OutS3:
380		mutex_unlock(&pm_mutex);
381		break;
382
383	case SNAPSHOT_PMOPS:
384		error = -EINVAL;
385
386		switch (arg) {
387
388		case PMOPS_PREPARE:
389			if (hibernation_ops) {
390				data->platform_suspend = 1;
391				error = 0;
392			} else {
393				error = -ENOSYS;
394			}
395			break;
396
397		case PMOPS_ENTER:
398			if (data->platform_suspend) {
399				kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
400				error = hibernation_ops->enter();
401			}
402			break;
403
404		case PMOPS_FINISH:
405			if (data->platform_suspend)
406				error = 0;
407
408			break;
409
410		default:
411			printk(KERN_ERR "SNAPSHOT_PMOPS: invalid argument %ld\n", arg);
412
413		}
414		break;
415
416	case SNAPSHOT_SET_SWAP_AREA:
417		if (swsusp_swap_in_use()) {
418			error = -EPERM;
419		} else {
420			struct resume_swap_area swap_area;
421			dev_t swdev;
422
423			error = copy_from_user(&swap_area, (void __user *)arg,
424					sizeof(struct resume_swap_area));
425			if (error) {
426				error = -EFAULT;
427				break;
428			}
429
430			/*
431			 * User space encodes device types as two-byte values,
432			 * so we need to recode them
433			 */
434			swdev = old_decode_dev(swap_area.dev);
435			if (swdev) {
436				offset = swap_area.offset;
437				data->swap = swap_type_of(swdev, offset, NULL);
438				if (data->swap < 0)
439					error = -ENODEV;
440			} else {
441				data->swap = -1;
442				error = -EINVAL;
443			}
444		}
445		break;
446
447	default:
448		error = -ENOTTY;
449
450	}
451
452	return error;
453}
454
455static const struct file_operations snapshot_fops = {
456	.open = snapshot_open,
457	.release = snapshot_release,
458	.read = snapshot_read,
459	.write = snapshot_write,
460	.llseek = no_llseek,
461	.ioctl = snapshot_ioctl,
462};
463
464static struct miscdevice snapshot_device = {
465	.minor = SNAPSHOT_MINOR,
466	.name = "snapshot",
467	.fops = &snapshot_fops,
468};
469
470static int __init snapshot_device_init(void)
471{
472	return misc_register(&snapshot_device);
473};
474
475device_initcall(snapshot_device_init);
476