Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/proc_fs.h>
3 : : #include <linux/seq_file.h>
4 : : #include <linux/export.h>
5 : : #include <linux/suspend.h>
6 : : #include <linux/bcd.h>
7 : : #include <linux/acpi.h>
8 : : #include <linux/uaccess.h>
9 : :
10 : : #include "sleep.h"
11 : : #include "internal.h"
12 : :
13 : : #define _COMPONENT ACPI_SYSTEM_COMPONENT
14 : :
15 : : /*
16 : : * this file provides support for:
17 : : * /proc/acpi/wakeup
18 : : */
19 : :
20 : : ACPI_MODULE_NAME("sleep")
21 : :
22 : : static int
23 : 0 : acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
24 : : {
25 : 0 : struct list_head *node, *next;
26 : :
27 : 0 : seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
28 : :
29 : 0 : mutex_lock(&acpi_device_lock);
30 [ # # ]: 0 : list_for_each_safe(node, next, &acpi_wakeup_device_list) {
31 : 0 : struct acpi_device *dev =
32 : 0 : container_of(node, struct acpi_device, wakeup_list);
33 : 0 : struct acpi_device_physical_node *entry;
34 : :
35 [ # # ]: 0 : if (!dev->wakeup.flags.valid)
36 : 0 : continue;
37 : :
38 : 0 : seq_printf(seq, "%s\t S%d\t",
39 : 0 : dev->pnp.bus_id,
40 : 0 : (u32) dev->wakeup.sleep_state);
41 : :
42 : 0 : mutex_lock(&dev->physical_node_lock);
43 : :
44 [ # # ]: 0 : if (!dev->physical_node_count) {
45 [ # # # # ]: 0 : seq_printf(seq, "%c%-8s\n",
46 [ # # ]: 0 : dev->wakeup.flags.valid ? '*' : ' ',
47 : : device_may_wakeup(&dev->dev) ?
48 : : "enabled" : "disabled");
49 : : } else {
50 : 0 : struct device *ldev;
51 [ # # ]: 0 : list_for_each_entry(entry, &dev->physical_node_list,
52 : : node) {
53 : 0 : ldev = get_device(entry->dev);
54 [ # # ]: 0 : if (!ldev)
55 : 0 : continue;
56 : :
57 : 0 : if (&entry->node !=
58 [ # # ]: 0 : dev->physical_node_list.next)
59 : 0 : seq_printf(seq, "\t\t");
60 : :
61 [ # # # # ]: 0 : seq_printf(seq, "%c%-8s %s:%s\n",
62 [ # # ]: 0 : dev->wakeup.flags.valid ? '*' : ' ',
63 [ # # ]: 0 : (device_may_wakeup(&dev->dev) ||
64 : : device_may_wakeup(ldev)) ?
65 : : "enabled" : "disabled",
66 [ # # ]: 0 : ldev->bus ? ldev->bus->name :
67 : : "no-bus", dev_name(ldev));
68 : 0 : put_device(ldev);
69 : : }
70 : : }
71 : :
72 : 0 : mutex_unlock(&dev->physical_node_lock);
73 : : }
74 : 0 : mutex_unlock(&acpi_device_lock);
75 : 0 : return 0;
76 : : }
77 : :
78 : 0 : static void physical_device_enable_wakeup(struct acpi_device *adev)
79 : : {
80 : 0 : struct acpi_device_physical_node *entry;
81 : :
82 : 0 : mutex_lock(&adev->physical_node_lock);
83 : :
84 [ # # ]: 0 : list_for_each_entry(entry,
85 : : &adev->physical_node_list, node)
86 [ # # # # ]: 0 : if (entry->dev && device_can_wakeup(entry->dev)) {
87 [ # # ]: 0 : bool enable = !device_may_wakeup(entry->dev);
88 : 0 : device_set_wakeup_enable(entry->dev, enable);
89 : : }
90 : :
91 : 0 : mutex_unlock(&adev->physical_node_lock);
92 : 0 : }
93 : :
94 : : static ssize_t
95 : 0 : acpi_system_write_wakeup_device(struct file *file,
96 : : const char __user * buffer,
97 : : size_t count, loff_t * ppos)
98 : : {
99 : 0 : struct list_head *node, *next;
100 : 0 : char strbuf[5];
101 : 0 : char str[5] = "";
102 : :
103 : 0 : if (count > 4)
104 : : count = 4;
105 : :
106 [ # # # # ]: 0 : if (copy_from_user(strbuf, buffer, count))
107 : : return -EFAULT;
108 : 0 : strbuf[count] = '\0';
109 : 0 : sscanf(strbuf, "%s", str);
110 : :
111 : 0 : mutex_lock(&acpi_device_lock);
112 [ # # ]: 0 : list_for_each_safe(node, next, &acpi_wakeup_device_list) {
113 : 0 : struct acpi_device *dev =
114 : 0 : container_of(node, struct acpi_device, wakeup_list);
115 [ # # ]: 0 : if (!dev->wakeup.flags.valid)
116 : 0 : continue;
117 : :
118 [ # # ]: 0 : if (!strncmp(dev->pnp.bus_id, str, 4)) {
119 [ # # ]: 0 : if (device_can_wakeup(&dev->dev)) {
120 [ # # ]: 0 : bool enable = !device_may_wakeup(&dev->dev);
121 : 0 : device_set_wakeup_enable(&dev->dev, enable);
122 : : } else {
123 : 0 : physical_device_enable_wakeup(dev);
124 : : }
125 : : break;
126 : : }
127 : : }
128 : 0 : mutex_unlock(&acpi_device_lock);
129 : 0 : return count;
130 : : }
131 : :
132 : : static int
133 : 0 : acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
134 : : {
135 : 0 : return single_open(file, acpi_system_wakeup_device_seq_show,
136 : : PDE_DATA(inode));
137 : : }
138 : :
139 : : static const struct proc_ops acpi_system_wakeup_device_proc_ops = {
140 : : .proc_open = acpi_system_wakeup_device_open_fs,
141 : : .proc_read = seq_read,
142 : : .proc_write = acpi_system_write_wakeup_device,
143 : : .proc_lseek = seq_lseek,
144 : : .proc_release = single_release,
145 : : };
146 : :
147 : 78 : void __init acpi_sleep_proc_init(void)
148 : : {
149 : : /* 'wakeup device' [R/W] */
150 : 78 : proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
151 : : acpi_root_dir, &acpi_system_wakeup_device_proc_ops);
152 : 78 : }
|