11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/seq_file.h>
3214f2c90b970e098e75cf719c0c5b0f1fe69b716Paul Gortmaker#include <linux/export.h>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/suspend.h>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bcd.h>
68b48463f89429af408ff695244dc627e1acff4f7Lv Zheng#include <linux/acpi.h>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sleep.h"
106a368751d54ed80e6ba868c29a04ad5118fe104bRashika#include "internal.h"
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _COMPONENT		ACPI_SYSTEM_COMPONENT
1343532c8a46ae313c2da3baa7598a1de4d403ba83Len Brown
1443532c8a46ae313c2da3baa7598a1de4d403ba83Len Brown/*
1543532c8a46ae313c2da3baa7598a1de4d403ba83Len Brown * this file provides support for:
1643532c8a46ae313c2da3baa7598a1de4d403ba83Len Brown * /proc/acpi/wakeup
1743532c8a46ae313c2da3baa7598a1de4d403ba83Len Brown */
1843532c8a46ae313c2da3baa7598a1de4d403ba83Len Brown
194be44fcd3bf648b782f4460fd06dfae6c42ded4bLen BrownACPI_MODULE_NAME("sleep")
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsacpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
244be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct list_head *node, *next;
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268aa55591bfea25c441117e82711cbfd7c274250aDavid Brownell	seq_printf(seq, "Device\tS-state\t  Status   Sysfs node\n");
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
289090589d87506c578ea1523ffd7ae7fd9424fb28Shaohua Li	mutex_lock(&acpi_device_lock);
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
304be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		struct acpi_device *dev =
314be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    container_of(node, struct acpi_device, wakeup_list);
321033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu		struct acpi_device_physical_node *entry;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!dev->wakeup.flags.valid)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
368aa55591bfea25c441117e82711cbfd7c274250aDavid Brownell
371033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu		seq_printf(seq, "%s\t  S%d\t",
384be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown			   dev->pnp.bus_id,
391033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			   (u32) dev->wakeup.sleep_state);
401033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu
41623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki		mutex_lock(&dev->physical_node_lock);
42623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki
4365ab96f60621c4da8f1b4087a57b788bc4d8f27bAndreas Fleig		if (!dev->physical_node_count) {
441033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			seq_printf(seq, "%c%-8s\n",
4565ab96f60621c4da8f1b4087a57b788bc4d8f27bAndreas Fleig				dev->wakeup.flags.run_wake ? '*' : ' ',
4665ab96f60621c4da8f1b4087a57b788bc4d8f27bAndreas Fleig				device_may_wakeup(&dev->dev) ?
4765ab96f60621c4da8f1b4087a57b788bc4d8f27bAndreas Fleig					"enabled" : "disabled");
4865ab96f60621c4da8f1b4087a57b788bc4d8f27bAndreas Fleig		} else {
491033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			struct device *ldev;
501033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			list_for_each_entry(entry, &dev->physical_node_list,
511033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					node) {
521033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu				ldev = get_device(entry->dev);
531033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu				if (!ldev)
541033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					continue;
551033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu
561033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu				if (&entry->node !=
571033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu						dev->physical_node_list.next)
581033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					seq_printf(seq, "\t\t");
591033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu
601033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu				seq_printf(seq, "%c%-8s  %s:%s\n",
611033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					dev->wakeup.flags.run_wake ? '*' : ' ',
621033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					(device_may_wakeup(&dev->dev) ||
63085ca1175cdccc8e400f6d06cf64e209b46021a2Dan Carpenter					device_may_wakeup(ldev)) ?
641033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					"enabled" : "disabled",
651033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					ldev->bus ? ldev->bus->name :
661033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu					"no-bus", dev_name(ldev));
671033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu				put_device(ldev);
681033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			}
691033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu		}
70623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki
71623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki		mutex_unlock(&dev->physical_node_lock);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
739090589d87506c578ea1523ffd7ae7fd9424fb28Shaohua Li	mutex_unlock(&acpi_device_lock);
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7776acae04c892287949e1191e99600f3e952e43f7Rafael J. Wysockistatic void physical_device_enable_wakeup(struct acpi_device *adev)
7876acae04c892287949e1191e99600f3e952e43f7Rafael J. Wysocki{
791033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu	struct acpi_device_physical_node *entry;
8076acae04c892287949e1191e99600f3e952e43f7Rafael J. Wysocki
81623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki	mutex_lock(&adev->physical_node_lock);
82623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki
831033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu	list_for_each_entry(entry,
841033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu		&adev->physical_node_list, node)
851033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu		if (entry->dev && device_can_wakeup(entry->dev)) {
861033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			bool enable = !device_may_wakeup(entry->dev);
871033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu			device_set_wakeup_enable(entry->dev, enable);
881033f9041d526dd694e2b2e12744e47c41040c4dLan Tianyu		}
89623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki
90623cf33cb055b1e81fa47e4fc16789b2c129e31eRafael J. Wysocki	mutex_unlock(&adev->physical_node_lock);
9176acae04c892287949e1191e99600f3e952e43f7Rafael J. Wysocki}
9276acae04c892287949e1191e99600f3e952e43f7Rafael J. Wysocki
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t
944be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brownacpi_system_write_wakeup_device(struct file *file,
954be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				const char __user * buffer,
964be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown				size_t count, loff_t * ppos)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
984be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	struct list_head *node, *next;
994be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	char strbuf[5];
1004be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	char str[5] = "";
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10205bce79e6d24ee6eb2beddf0f6314358404d472fCyril Roelandt	if (count > 4)
10305bce79e6d24ee6eb2beddf0f6314358404d472fCyril Roelandt		count = 4;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10505bce79e6d24ee6eb2beddf0f6314358404d472fCyril Roelandt	if (copy_from_user(strbuf, buffer, count))
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EFAULT;
10705bce79e6d24ee6eb2beddf0f6314358404d472fCyril Roelandt	strbuf[count] = '\0';
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sscanf(strbuf, "%s", str);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1109090589d87506c578ea1523ffd7ae7fd9424fb28Shaohua Li	mutex_lock(&acpi_device_lock);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_for_each_safe(node, next, &acpi_wakeup_device_list) {
1124be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		struct acpi_device *dev =
1134be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown		    container_of(node, struct acpi_device, wakeup_list);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!dev->wakeup.flags.valid)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			continue;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!strncmp(dev->pnp.bus_id, str, 4)) {
118f2b56bc808addb908a5bf435d9b942c02af9a7c4Rafael J. Wysocki			if (device_can_wakeup(&dev->dev)) {
119f2b56bc808addb908a5bf435d9b942c02af9a7c4Rafael J. Wysocki				bool enable = !device_may_wakeup(&dev->dev);
120f2b56bc808addb908a5bf435d9b942c02af9a7c4Rafael J. Wysocki				device_set_wakeup_enable(&dev->dev, enable);
121f2b56bc808addb908a5bf435d9b942c02af9a7c4Rafael J. Wysocki			} else {
122f2b56bc808addb908a5bf435d9b942c02af9a7c4Rafael J. Wysocki				physical_device_enable_wakeup(dev);
123f2b56bc808addb908a5bf435d9b942c02af9a7c4Rafael J. Wysocki			}
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1279090589d87506c578ea1523ffd7ae7fd9424fb28Shaohua Li	mutex_unlock(&acpi_device_lock);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsacpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1344be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	return single_open(file, acpi_system_wakeup_device_seq_show,
135d9dda78bad879595d8c4220a067fc029d6484a16Al Viro			   PDE_DATA(inode));
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
138d75080328affb4b268da430b7074cc8139cc662aArjan van de Venstatic const struct file_operations acpi_system_wakeup_device_fops = {
139cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	.owner = THIS_MODULE,
1404be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.open = acpi_system_wakeup_device_open_fs,
1414be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.read = seq_read,
1424be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.write = acpi_system_write_wakeup_device,
1434be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.llseek = seq_lseek,
1444be44fcd3bf648b782f4460fd06dfae6c42ded4bLen Brown	.release = single_release,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1479cee43e07940bee13462e63bd75ce4430b155886Bjorn Helgaasint __init acpi_sleep_proc_init(void)
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
149c65ade4dc8b486e8c8b9b0a6399789a5428e2039Pavel Machek	/* 'wakeup device' [R/W] */
150cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
151cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev		    acpi_root_dir, &acpi_system_wakeup_device_fops);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
155