blob: 6a5b152ad4d070511d08d74439155fa17a83ed8a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#include <linux/proc_fs.h>
2#include <linux/seq_file.h>
Paul Gortmaker214f2c92011-10-26 16:22:14 -04003#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004#include <linux/suspend.h>
5#include <linux/bcd.h>
6#include <asm/uaccess.h>
7
8#include <acpi/acpi_bus.h>
9#include <acpi/acpi_drivers.h>
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include "sleep.h"
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#define _COMPONENT ACPI_SYSTEM_COMPONENT
Len Brown43532c82007-07-24 02:16:50 -040014
15/*
16 * this file provides support for:
Len Brown43532c82007-07-24 02:16:50 -040017 * /proc/acpi/wakeup
18 */
19
Len Brown4be44fc2005-08-05 00:44:28 -040020ACPI_MODULE_NAME("sleep")
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Linus Torvalds1da177e2005-04-16 15:20:36 -070022static int
23acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
24{
Len Brown4be44fc2005-08-05 00:44:28 -040025 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
David Brownell8aa55592007-04-25 15:20:10 -040027 seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Shaohua Li90905892009-04-07 10:24:29 +080029 mutex_lock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -040031 struct acpi_device *dev =
32 container_of(node, struct acpi_device, wakeup_list);
Lan Tianyu1033f902012-08-17 14:44:09 +080033 struct acpi_device_physical_node *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35 if (!dev->wakeup.flags.valid)
36 continue;
David Brownell8aa55592007-04-25 15:20:10 -040037
Lan Tianyu1033f902012-08-17 14:44:09 +080038 seq_printf(seq, "%s\t S%d\t",
Len Brown4be44fc2005-08-05 00:44:28 -040039 dev->pnp.bus_id,
Lan Tianyu1033f902012-08-17 14:44:09 +080040 (u32) dev->wakeup.sleep_state);
David Brownell8aa55592007-04-25 15:20:10 -040041
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020042 mutex_lock(&dev->physical_node_lock);
43
Andreas Fleig65ab96f2013-01-27 14:17:55 +000044 if (!dev->physical_node_count) {
Lan Tianyu1033f902012-08-17 14:44:09 +080045 seq_printf(seq, "%c%-8s\n",
Andreas Fleig65ab96f2013-01-27 14:17:55 +000046 dev->wakeup.flags.run_wake ? '*' : ' ',
47 device_may_wakeup(&dev->dev) ?
48 "enabled" : "disabled");
49 } else {
Lan Tianyu1033f902012-08-17 14:44:09 +080050 struct device *ldev;
51 list_for_each_entry(entry, &dev->physical_node_list,
52 node) {
53 ldev = get_device(entry->dev);
54 if (!ldev)
55 continue;
56
57 if (&entry->node !=
58 dev->physical_node_list.next)
59 seq_printf(seq, "\t\t");
60
61 seq_printf(seq, "%c%-8s %s:%s\n",
62 dev->wakeup.flags.run_wake ? '*' : ' ',
63 (device_may_wakeup(&dev->dev) ||
64 (ldev && device_may_wakeup(ldev))) ?
65 "enabled" : "disabled",
66 ldev->bus ? ldev->bus->name :
67 "no-bus", dev_name(ldev));
68 put_device(ldev);
69 }
70 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020071
72 mutex_unlock(&dev->physical_node_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 }
Shaohua Li90905892009-04-07 10:24:29 +080074 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 return 0;
76}
77
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070078static void physical_device_enable_wakeup(struct acpi_device *adev)
79{
Lan Tianyu1033f902012-08-17 14:44:09 +080080 struct acpi_device_physical_node *entry;
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070081
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020082 mutex_lock(&adev->physical_node_lock);
83
Lan Tianyu1033f902012-08-17 14:44:09 +080084 list_for_each_entry(entry,
85 &adev->physical_node_list, node)
86 if (entry->dev && device_can_wakeup(entry->dev)) {
87 bool enable = !device_may_wakeup(entry->dev);
88 device_set_wakeup_enable(entry->dev, enable);
89 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020090
91 mutex_unlock(&adev->physical_node_lock);
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070092}
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094static ssize_t
Len Brown4be44fc2005-08-05 00:44:28 -040095acpi_system_write_wakeup_device(struct file *file,
96 const char __user * buffer,
97 size_t count, loff_t * ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
Len Brown4be44fc2005-08-05 00:44:28 -040099 struct list_head *node, *next;
100 char strbuf[5];
101 char str[5] = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Cyril Roelandt05bce792012-11-22 23:20:31 +0100103 if (count > 4)
104 count = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Cyril Roelandt05bce792012-11-22 23:20:31 +0100106 if (copy_from_user(strbuf, buffer, count))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 return -EFAULT;
Cyril Roelandt05bce792012-11-22 23:20:31 +0100108 strbuf[count] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 sscanf(strbuf, "%s", str);
110
Shaohua Li90905892009-04-07 10:24:29 +0800111 mutex_lock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400113 struct acpi_device *dev =
114 container_of(node, struct acpi_device, wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 if (!dev->wakeup.flags.valid)
116 continue;
117
118 if (!strncmp(dev->pnp.bus_id, str, 4)) {
Rafael J. Wysockif2b56bc2011-01-06 23:34:22 +0100119 if (device_can_wakeup(&dev->dev)) {
120 bool enable = !device_may_wakeup(&dev->dev);
121 device_set_wakeup_enable(&dev->dev, enable);
122 } else {
123 physical_device_enable_wakeup(dev);
124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 break;
126 }
127 }
Shaohua Li90905892009-04-07 10:24:29 +0800128 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 return count;
130}
131
132static int
133acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
134{
Len Brown4be44fc2005-08-05 00:44:28 -0400135 return single_open(file, acpi_system_wakeup_device_seq_show,
Al Virod9dda782013-03-31 18:16:14 -0400136 PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Arjan van de Vend7508032006-07-04 13:06:00 -0400139static const struct file_operations acpi_system_wakeup_device_fops = {
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700140 .owner = THIS_MODULE,
Len Brown4be44fc2005-08-05 00:44:28 -0400141 .open = acpi_system_wakeup_device_open_fs,
142 .read = seq_read,
143 .write = acpi_system_write_wakeup_device,
144 .llseek = seq_lseek,
145 .release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146};
147
Bjorn Helgaas9cee43e2009-03-24 16:50:14 -0600148int __init acpi_sleep_proc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Pavel Machekc65ade42005-08-05 00:37:45 -0400150 /* 'wakeup device' [R/W] */
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700151 proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
152 acpi_root_dir, &acpi_system_wakeup_device_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 return 0;
155}