linux/drivers/acpi/proc.c
Rafael J. Wysocki a1a66393e3 ACPI / PM: Drop run_wake from struct acpi_device_wakeup_flags
The run_wake flag in struct acpi_device_wakeup_flags stores the
information on whether or not the device can generate wakeup
signals at run time, but in ACPI that really is equivalent to
being able to generate wakeup signals at all.

In fact, run_wake will always be set after successful executeion of
acpi_setup_gpe_for_wake(), but if that fails, the device will not be
able to use a wakeup GPE at all, so it won't be able to wake up the
systems from sleep states too.  Hence, run_wake actually means that
the device is capable of triggering wakeup and so it is equivalent
to the valid flag.

For this reason, drop run_wake from struct acpi_device_wakeup_flags
and make sure that the valid flag is only set if
acpi_setup_gpe_for_wake() has been successful.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
2017-06-28 01:52:15 +02:00

153 lines
3.6 KiB
C

#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/bcd.h>
#include <linux/acpi.h>
#include <linux/uaccess.h>
#include "sleep.h"
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
/*
* this file provides support for:
* /proc/acpi/wakeup
*/
ACPI_MODULE_NAME("sleep")
static int
acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
{
struct list_head *node, *next;
seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
mutex_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list);
struct acpi_device_physical_node *entry;
if (!dev->wakeup.flags.valid)
continue;
seq_printf(seq, "%s\t S%d\t",
dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state);
mutex_lock(&dev->physical_node_lock);
if (!dev->physical_node_count) {
seq_printf(seq, "%c%-8s\n",
dev->wakeup.flags.valid ? '*' : ' ',
device_may_wakeup(&dev->dev) ?
"enabled" : "disabled");
} else {
struct device *ldev;
list_for_each_entry(entry, &dev->physical_node_list,
node) {
ldev = get_device(entry->dev);
if (!ldev)
continue;
if (&entry->node !=
dev->physical_node_list.next)
seq_printf(seq, "\t\t");
seq_printf(seq, "%c%-8s %s:%s\n",
dev->wakeup.flags.valid ? '*' : ' ',
(device_may_wakeup(&dev->dev) ||
device_may_wakeup(ldev)) ?
"enabled" : "disabled",
ldev->bus ? ldev->bus->name :
"no-bus", dev_name(ldev));
put_device(ldev);
}
}
mutex_unlock(&dev->physical_node_lock);
}
mutex_unlock(&acpi_device_lock);
return 0;
}
static void physical_device_enable_wakeup(struct acpi_device *adev)
{
struct acpi_device_physical_node *entry;
mutex_lock(&adev->physical_node_lock);
list_for_each_entry(entry,
&adev->physical_node_list, node)
if (entry->dev && device_can_wakeup(entry->dev)) {
bool enable = !device_may_wakeup(entry->dev);
device_set_wakeup_enable(entry->dev, enable);
}
mutex_unlock(&adev->physical_node_lock);
}
static ssize_t
acpi_system_write_wakeup_device(struct file *file,
const char __user * buffer,
size_t count, loff_t * ppos)
{
struct list_head *node, *next;
char strbuf[5];
char str[5] = "";
if (count > 4)
count = 4;
if (copy_from_user(strbuf, buffer, count))
return -EFAULT;
strbuf[count] = '\0';
sscanf(strbuf, "%s", str);
mutex_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list);
if (!dev->wakeup.flags.valid)
continue;
if (!strncmp(dev->pnp.bus_id, str, 4)) {
if (device_can_wakeup(&dev->dev)) {
bool enable = !device_may_wakeup(&dev->dev);
device_set_wakeup_enable(&dev->dev, enable);
} else {
physical_device_enable_wakeup(dev);
}
break;
}
}
mutex_unlock(&acpi_device_lock);
return count;
}
static int
acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
{
return single_open(file, acpi_system_wakeup_device_seq_show,
PDE_DATA(inode));
}
static const struct file_operations acpi_system_wakeup_device_fops = {
.owner = THIS_MODULE,
.open = acpi_system_wakeup_device_open_fs,
.read = seq_read,
.write = acpi_system_write_wakeup_device,
.llseek = seq_lseek,
.release = single_release,
};
void __init acpi_sleep_proc_init(void)
{
/* 'wakeup device' [R/W] */
proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
acpi_root_dir, &acpi_system_wakeup_device_fops);
}