blob: 0cca7991f18643c98ed2cf1f9328b98b2e9b76fb [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
Len Brown43532c82007-07-24 02:16:50 -040013/*
14 * this file provides support for:
Len Brown43532c82007-07-24 02:16:50 -040015 * /proc/acpi/wakeup
16 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018static int
19acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
20{
chenqiwu07761a42020-02-23 14:08:22 +080021 struct acpi_device *dev, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
David Brownell8aa55592007-04-25 15:20:10 -040023 seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Shaohua Li90905892009-04-07 10:24:29 +080025 mutex_lock(&acpi_device_lock);
chenqiwu07761a42020-02-23 14:08:22 +080026 list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
27 wakeup_list) {
Lan Tianyu1033f902012-08-17 14:44:09 +080028 struct acpi_device_physical_node *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30 if (!dev->wakeup.flags.valid)
31 continue;
David Brownell8aa55592007-04-25 15:20:10 -040032
Lan Tianyu1033f902012-08-17 14:44:09 +080033 seq_printf(seq, "%s\t S%d\t",
Len Brown4be44fc2005-08-05 00:44:28 -040034 dev->pnp.bus_id,
Lan Tianyu1033f902012-08-17 14:44:09 +080035 (u32) dev->wakeup.sleep_state);
David Brownell8aa55592007-04-25 15:20:10 -040036
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020037 mutex_lock(&dev->physical_node_lock);
38
Andreas Fleig65ab96f2013-01-27 14:17:55 +000039 if (!dev->physical_node_count) {
Lan Tianyu1033f902012-08-17 14:44:09 +080040 seq_printf(seq, "%c%-8s\n",
Rafael J. Wysockia1a66392017-06-24 01:53:14 +020041 dev->wakeup.flags.valid ? '*' : ' ',
Andreas Fleig65ab96f2013-01-27 14:17:55 +000042 device_may_wakeup(&dev->dev) ?
43 "enabled" : "disabled");
44 } else {
Lan Tianyu1033f902012-08-17 14:44:09 +080045 struct device *ldev;
46 list_for_each_entry(entry, &dev->physical_node_list,
47 node) {
48 ldev = get_device(entry->dev);
49 if (!ldev)
50 continue;
51
52 if (&entry->node !=
53 dev->physical_node_list.next)
54 seq_printf(seq, "\t\t");
55
56 seq_printf(seq, "%c%-8s %s:%s\n",
Rafael J. Wysockia1a66392017-06-24 01:53:14 +020057 dev->wakeup.flags.valid ? '*' : ' ',
Lan Tianyu1033f902012-08-17 14:44:09 +080058 (device_may_wakeup(&dev->dev) ||
Dan Carpenter085ca112014-01-30 14:55:15 +030059 device_may_wakeup(ldev)) ?
Lan Tianyu1033f902012-08-17 14:44:09 +080060 "enabled" : "disabled",
61 ldev->bus ? ldev->bus->name :
62 "no-bus", dev_name(ldev));
63 put_device(ldev);
64 }
65 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020066
67 mutex_unlock(&dev->physical_node_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 }
Shaohua Li90905892009-04-07 10:24:29 +080069 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 return 0;
71}
72
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070073static void physical_device_enable_wakeup(struct acpi_device *adev)
74{
Lan Tianyu1033f902012-08-17 14:44:09 +080075 struct acpi_device_physical_node *entry;
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070076
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020077 mutex_lock(&adev->physical_node_lock);
78
Lan Tianyu1033f902012-08-17 14:44:09 +080079 list_for_each_entry(entry,
80 &adev->physical_node_list, node)
81 if (entry->dev && device_can_wakeup(entry->dev)) {
82 bool enable = !device_may_wakeup(entry->dev);
83 device_set_wakeup_enable(entry->dev, enable);
84 }
Rafael J. Wysocki623cf332013-08-06 02:26:22 +020085
86 mutex_unlock(&adev->physical_node_lock);
Rafael J. Wysocki76acae02008-10-03 15:23:49 -070087}
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static ssize_t
Len Brown4be44fc2005-08-05 00:44:28 -040090acpi_system_write_wakeup_device(struct file *file,
91 const char __user * buffer,
92 size_t count, loff_t * ppos)
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
chenqiwu07761a42020-02-23 14:08:22 +080094 struct acpi_device *dev, *tmp;
Len Brown4be44fc2005-08-05 00:44:28 -040095 char strbuf[5];
96 char str[5] = "";
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Cyril Roelandt05bce792012-11-22 23:20:31 +010098 if (count > 4)
99 count = 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Cyril Roelandt05bce792012-11-22 23:20:31 +0100101 if (copy_from_user(strbuf, buffer, count))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 return -EFAULT;
Cyril Roelandt05bce792012-11-22 23:20:31 +0100103 strbuf[count] = '\0';
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 sscanf(strbuf, "%s", str);
105
Shaohua Li90905892009-04-07 10:24:29 +0800106 mutex_lock(&acpi_device_lock);
chenqiwu07761a42020-02-23 14:08:22 +0800107 list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
108 wakeup_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 if (!dev->wakeup.flags.valid)
110 continue;
111
112 if (!strncmp(dev->pnp.bus_id, str, 4)) {
Rafael J. Wysockif2b56bc2011-01-06 23:34:22 +0100113 if (device_can_wakeup(&dev->dev)) {
114 bool enable = !device_may_wakeup(&dev->dev);
115 device_set_wakeup_enable(&dev->dev, enable);
116 } else {
117 physical_device_enable_wakeup(dev);
118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 break;
120 }
121 }
Shaohua Li90905892009-04-07 10:24:29 +0800122 mutex_unlock(&acpi_device_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return count;
124}
125
126static int
127acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
128{
Len Brown4be44fc2005-08-05 00:44:28 -0400129 return single_open(file, acpi_system_wakeup_device_seq_show,
Al Virod9dda782013-03-31 18:16:14 -0400130 PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
Alexey Dobriyan97a32532020-02-03 17:37:17 -0800133static const struct proc_ops acpi_system_wakeup_device_proc_ops = {
134 .proc_open = acpi_system_wakeup_device_open_fs,
135 .proc_read = seq_read,
136 .proc_write = acpi_system_write_wakeup_device,
137 .proc_lseek = seq_lseek,
138 .proc_release = single_release,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139};
140
Rami Rosenf934c742015-09-11 17:49:22 +0300141void __init acpi_sleep_proc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Pavel Machekc65ade42005-08-05 00:37:45 -0400143 /* 'wakeup device' [R/W] */
Denis V. Lunevcf7acfa2008-04-29 01:02:27 -0700144 proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
Alexey Dobriyan97a32532020-02-03 17:37:17 -0800145 acpi_root_dir, &acpi_system_wakeup_device_proc_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}