blob: 75c28eae88604903ac518fc0fe4ebe83f2e2669e [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"
Rashika6a368752013-12-17 15:04:17 +053010#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070011
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#define _COMPONENT ACPI_SYSTEM_COMPONENT
Len Brown43532c82007-07-24 02:16:50 -040013
14/*
15 * this file provides support for:
Len Brown43532c82007-07-24 02:16:50 -040016 * /proc/acpi/wakeup
17 */
18
Len Brown4be44fc2005-08-05 00:44:28 -040019ACPI_MODULE_NAME("sleep")
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Linus Torvalds1da177e2005-04-16 15:20:36 -070021static int
22acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
23{
Len Brown4be44fc2005-08-05 00:44:28 -040024 struct list_head *node, *next;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
David Brownell8aa55592007-04-25 15:20:10 -040026 seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Shaohua Li90905892009-04-07 10:24:29 +080028 mutex_lock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -040030 struct acpi_device *dev =
31 container_of(node, struct acpi_device, wakeup_list);
Lan Tianyu1033f902012-08-17 14:44:09 +080032 struct acpi_device_physical_node *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34 if (!dev->wakeup.flags.valid)
35 continue;
David Brownell8aa55592007-04-25 15:20:10 -040036
Lan Tianyu1033f902012-08-17 14:44:09 +080037 seq_printf(seq, "%s\t S%d\t",
Len Brown4be44fc2005-08-05 00:44:28 -040038 dev->pnp.bus_id,
Lan Tianyu1033f902012-08-17 14:44:09 +080039 (u32) dev->wakeup.sleep_state);
David Brownell8aa55592007-04-25 15:20:10 -040040
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020041 mutex_lock(&dev->physical_node_lock);
42
Andreas Fleig65ab96f2013-01-27 14:17:55 +000043 if (!dev->physical_node_count) {
Lan Tianyu1033f902012-08-17 14:44:09 +080044 seq_printf(seq, "%c%-8s\n",
Andreas Fleig65ab96f2013-01-27 14:17:55 +000045 dev->wakeup.flags.run_wake ? '*' : ' ',
46 device_may_wakeup(&dev->dev) ?
47 "enabled" : "disabled");
48 } else {
Lan Tianyu1033f902012-08-17 14:44:09 +080049 struct device *ldev;
50 list_for_each_entry(entry, &dev->physical_node_list,
51 node) {
52 ldev = get_device(entry->dev);
53 if (!ldev)
54 continue;
55
56 if (&entry->node !=
57 dev->physical_node_list.next)
58 seq_printf(seq, "\t\t");
59
60 seq_printf(seq, "%c%-8s %s:%s\n",
61 dev->wakeup.flags.run_wake ? '*' : ' ',
62 (device_may_wakeup(&dev->dev) ||
Dan Carpenter085ca112014-01-30 14:55:15 +030063 device_may_wakeup(ldev)) ?
Lan Tianyu1033f902012-08-17 14:44:09 +080064 "enabled" : "disabled",
65 ldev->bus ? ldev->bus->name :
66 "no-bus", dev_name(ldev));
67 put_device(ldev);
68 }
69 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020070
71 mutex_unlock(&dev->physical_node_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 }
Shaohua Li90905892009-04-07 10:24:29 +080073 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 return 0;
75}
76
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070077static void physical_device_enable_wakeup(struct acpi_device *adev)
78{
Lan Tianyu1033f902012-08-17 14:44:09 +080079 struct acpi_device_physical_node *entry;
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070080
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020081 mutex_lock(&adev->physical_node_lock);
82
Lan Tianyu1033f902012-08-17 14:44:09 +080083 list_for_each_entry(entry,
84 &adev->physical_node_list, node)
85 if (entry->dev && device_can_wakeup(entry->dev)) {
86 bool enable = !device_may_wakeup(entry->dev);
87 device_set_wakeup_enable(entry->dev, enable);
88 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020089
90 mutex_unlock(&adev->physical_node_lock);
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070091}
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static ssize_t
Len Brown4be44fc2005-08-05 00:44:28 -040094acpi_system_write_wakeup_device(struct file *file,
95 const char __user * buffer,
96 size_t count, loff_t * ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097{
Len Brown4be44fc2005-08-05 00:44:28 -040098 struct list_head *node, *next;
99 char strbuf[5];
100 char str[5] = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Cyril Roelandt05bce792012-11-22 23:20:31 +0100102 if (count > 4)
103 count = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Cyril Roelandt05bce792012-11-22 23:20:31 +0100105 if (copy_from_user(strbuf, buffer, count))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 return -EFAULT;
Cyril Roelandt05bce792012-11-22 23:20:31 +0100107 strbuf[count] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 sscanf(strbuf, "%s", str);
109
Shaohua Li90905892009-04-07 10:24:29 +0800110 mutex_lock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 list_for_each_safe(node, next, &acpi_wakeup_device_list) {
Len Brown4be44fc2005-08-05 00:44:28 -0400112 struct acpi_device *dev =
113 container_of(node, struct acpi_device, wakeup_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 if (!dev->wakeup.flags.valid)
115 continue;
116
117 if (!strncmp(dev->pnp.bus_id, str, 4)) {
Rafael J. Wysockif2b56bc2011-01-06 23:34:22 +0100118 if (device_can_wakeup(&dev->dev)) {
119 bool enable = !device_may_wakeup(&dev->dev);
120 device_set_wakeup_enable(&dev->dev, enable);
121 } else {
122 physical_device_enable_wakeup(dev);
123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 break;
125 }
126 }
Shaohua Li90905892009-04-07 10:24:29 +0800127 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 return count;
129}
130
131static int
132acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
133{
Len Brown4be44fc2005-08-05 00:44:28 -0400134 return single_open(file, acpi_system_wakeup_device_seq_show,
Al Virod9dda782013-03-31 18:16:14 -0400135 PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Arjan van de Vend7508032006-07-04 13:06:00 -0400138static const struct file_operations acpi_system_wakeup_device_fops = {
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700139 .owner = THIS_MODULE,
Len Brown4be44fc2005-08-05 00:44:28 -0400140 .open = acpi_system_wakeup_device_open_fs,
141 .read = seq_read,
142 .write = acpi_system_write_wakeup_device,
143 .llseek = seq_lseek,
144 .release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145};
146
Bjorn Helgaas9cee43e2009-03-24 16:50:14 -0600147int __init acpi_sleep_proc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
Pavel Machekc65ade42005-08-05 00:37:45 -0400149 /* 'wakeup device' [R/W] */
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700150 proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
151 acpi_root_dir, &acpi_system_wakeup_device_fops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return 0;
154}