blob: db061bfd95a8de20aea42e95ae0bda75c6b68a9f [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>
Lv Zheng8b484632013-12-03 08:49:16 +08006#include <linux/acpi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include <asm/uaccess.h>
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include "sleep.h"
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#define _COMPONENT ACPI_SYSTEM_COMPONENT
Len Brown43532c82007-07-24 02:16:50 -040012
13/*
14 * this file provides support for:
Len Brown43532c82007-07-24 02:16:50 -040015 * /proc/acpi/wakeup
16 */
17
Len Brown4be44fc2005-08-05 00:44:28 -040018ACPI_MODULE_NAME("sleep")
Linus Torvalds1da177e2005-04-16 15:20:36 -070019
Linus Torvalds1da177e2005-04-16 15:20:36 -070020static int
21acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
22{
Len Brown4be44fc2005-08-05 00:44:28 -040023 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
David Brownell8aa55592007-04-25 15:20:10 -040025 seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Shaohua Li90905892009-04-07 10:24:29 +080027 mutex_lock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -040029 struct acpi_device *dev =
30 container_of(node, struct acpi_device, wakeup_list);
Lan Tianyu1033f902012-08-17 14:44:09 +080031 struct acpi_device_physical_node *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33 if (!dev->wakeup.flags.valid)
34 continue;
David Brownell8aa55592007-04-25 15:20:10 -040035
Lan Tianyu1033f902012-08-17 14:44:09 +080036 seq_printf(seq, "%s\t S%d\t",
Len Brown4be44fc2005-08-05 00:44:28 -040037 dev->pnp.bus_id,
Lan Tianyu1033f902012-08-17 14:44:09 +080038 (u32) dev->wakeup.sleep_state);
David Brownell8aa55592007-04-25 15:20:10 -040039
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020040 mutex_lock(&dev->physical_node_lock);
41
Andreas Fleig65ab96f2013-01-27 14:17:55 +000042 if (!dev->physical_node_count) {
Lan Tianyu1033f902012-08-17 14:44:09 +080043 seq_printf(seq, "%c%-8s\n",
Andreas Fleig65ab96f2013-01-27 14:17:55 +000044 dev->wakeup.flags.run_wake ? '*' : ' ',
45 device_may_wakeup(&dev->dev) ?
46 "enabled" : "disabled");
47 } else {
Lan Tianyu1033f902012-08-17 14:44:09 +080048 struct device *ldev;
49 list_for_each_entry(entry, &dev->physical_node_list,
50 node) {
51 ldev = get_device(entry->dev);
52 if (!ldev)
53 continue;
54
55 if (&entry->node !=
56 dev->physical_node_list.next)
57 seq_printf(seq, "\t\t");
58
59 seq_printf(seq, "%c%-8s %s:%s\n",
60 dev->wakeup.flags.run_wake ? '*' : ' ',
61 (device_may_wakeup(&dev->dev) ||
62 (ldev && device_may_wakeup(ldev))) ?
63 "enabled" : "disabled",
64 ldev->bus ? ldev->bus->name :
65 "no-bus", dev_name(ldev));
66 put_device(ldev);
67 }
68 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020069
70 mutex_unlock(&dev->physical_node_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 }
Shaohua Li90905892009-04-07 10:24:29 +080072 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 return 0;
74}
75
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070076static void physical_device_enable_wakeup(struct acpi_device *adev)
77{
Lan Tianyu1033f902012-08-17 14:44:09 +080078 struct acpi_device_physical_node *entry;
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070079
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020080 mutex_lock(&adev->physical_node_lock);
81
Lan Tianyu1033f902012-08-17 14:44:09 +080082 list_for_each_entry(entry,
83 &adev->physical_node_list, node)
84 if (entry->dev && device_can_wakeup(entry->dev)) {
85 bool enable = !device_may_wakeup(entry->dev);
86 device_set_wakeup_enable(entry->dev, enable);
87 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020088
89 mutex_unlock(&adev->physical_node_lock);
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070090}
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092static ssize_t
Len Brown4be44fc2005-08-05 00:44:28 -040093acpi_system_write_wakeup_device(struct file *file,
94 const char __user * buffer,
95 size_t count, loff_t * ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
Len Brown4be44fc2005-08-05 00:44:28 -040097 struct list_head *node, *next;
98 char strbuf[5];
99 char str[5] = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Cyril Roelandt05bce792012-11-22 23:20:31 +0100101 if (count > 4)
102 count = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Cyril Roelandt05bce792012-11-22 23:20:31 +0100104 if (copy_from_user(strbuf, buffer, count))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return -EFAULT;
Cyril Roelandt05bce792012-11-22 23:20:31 +0100106 strbuf[count] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 sscanf(strbuf, "%s", str);
108
Shaohua Li90905892009-04-07 10:24:29 +0800109 mutex_lock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400111 struct acpi_device *dev =
112 container_of(node, struct acpi_device, wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 if (!dev->wakeup.flags.valid)
114 continue;
115
116 if (!strncmp(dev->pnp.bus_id, str, 4)) {
Rafael J. Wysockif2b56bc2011-01-06 23:34:22 +0100117 if (device_can_wakeup(&dev->dev)) {
118 bool enable = !device_may_wakeup(&dev->dev);
119 device_set_wakeup_enable(&dev->dev, enable);
120 } else {
121 physical_device_enable_wakeup(dev);
122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 break;
124 }
125 }
Shaohua Li90905892009-04-07 10:24:29 +0800126 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 return count;
128}
129
130static int
131acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
132{
Len Brown4be44fc2005-08-05 00:44:28 -0400133 return single_open(file, acpi_system_wakeup_device_seq_show,
Al Virod9dda782013-03-31 18:16:14 -0400134 PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135}
136
Arjan van de Vend7508032006-07-04 13:06:00 -0400137static const struct file_operations acpi_system_wakeup_device_fops = {
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700138 .owner = THIS_MODULE,
Len Brown4be44fc2005-08-05 00:44:28 -0400139 .open = acpi_system_wakeup_device_open_fs,
140 .read = seq_read,
141 .write = acpi_system_write_wakeup_device,
142 .llseek = seq_lseek,
143 .release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144};
145
Bjorn Helgaas9cee43e2009-03-24 16:50:14 -0600146int __init acpi_sleep_proc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
Pavel Machekc65ade42005-08-05 00:37:45 -0400148 /* 'wakeup device' [R/W] */
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700149 proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
150 acpi_root_dir, &acpi_system_wakeup_device_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 return 0;
153}