blob: 7892980b3ce4d3b4e0769d710084d154d3a4006a [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#include <linux/proc_fs.h>
3#include <linux/seq_file.h>
Paul Gortmaker214f2c92011-10-26 16:22:14 -04004#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005#include <linux/suspend.h>
6#include <linux/bcd.h>
Lv Zheng8b484632013-12-03 08:49:16 +08007#include <linux/acpi.h>
Linus Torvalds7c0f6ba2016-12-24 11:46:01 -08008#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include "sleep.h"
Rashika6a368752013-12-17 15:04:17 +053011#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
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{
chenqiwu07761a42020-02-23 14:08:22 +080025 struct acpi_device *dev, *tmp;
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);
chenqiwu07761a42020-02-23 14:08:22 +080030 list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
31 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",
Rafael J. Wysockia1a66392017-06-24 01:53:14 +020045 dev->wakeup.flags.valid ? '*' : ' ',
Andreas Fleig65ab96f2013-01-27 14:17:55 +000046 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",
Rafael J. Wysockia1a66392017-06-24 01:53:14 +020061 dev->wakeup.flags.valid ? '*' : ' ',
Lan Tianyu1033f902012-08-17 14:44:09 +080062 (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{
chenqiwu07761a42020-02-23 14:08:22 +080098 struct acpi_device *dev, *tmp;
Len Brown4be44fc2005-08-05 00:44:28 -040099 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);
chenqiwu07761a42020-02-23 14:08:22 +0800111 list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
112 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
Alexey Dobriyan97a32532020-02-03 17:37:17 -0800137static const struct proc_ops acpi_system_wakeup_device_proc_ops = {
138 .proc_open = acpi_system_wakeup_device_open_fs,
139 .proc_read = seq_read,
140 .proc_write = acpi_system_write_wakeup_device,
141 .proc_lseek = seq_lseek,
142 .proc_release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143};
144
Rami Rosenf934c742015-09-11 17:49:22 +0300145void __init acpi_sleep_proc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Pavel Machekc65ade42005-08-05 00:37:45 -0400147 /* 'wakeup device' [R/W] */
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700148 proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
Alexey Dobriyan97a32532020-02-03 17:37:17 -0800149 acpi_root_dir, &acpi_system_wakeup_device_proc_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150}