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