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/*
  14 * this file provides support for:
  15 * /proc/acpi/wakeup
  16 */
  17
  18static int
  19acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
  20{
  21        struct acpi_device *dev, *tmp;
  22
  23        seq_printf(seq, "Device\tS-state\t  Status   Sysfs node\n");
  24
  25        mutex_lock(&acpi_device_lock);
  26        list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
  27                                 wakeup_list) {
  28                struct acpi_device_physical_node *entry;
  29
  30                if (!dev->wakeup.flags.valid)
  31                        continue;
  32
  33                seq_printf(seq, "%s\t  S%d\t",
  34                           dev->pnp.bus_id,
  35                           (u32) dev->wakeup.sleep_state);
  36
  37                mutex_lock(&dev->physical_node_lock);
  38
  39                if (!dev->physical_node_count) {
  40                        seq_printf(seq, "%c%-8s\n",
  41                                dev->wakeup.flags.valid ? '*' : ' ',
  42                                device_may_wakeup(&dev->dev) ?
  43                                        "enabled" : "disabled");
  44                } else {
  45                        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",
  57                                        dev->wakeup.flags.valid ? '*' : ' ',
  58                                        (device_may_wakeup(&dev->dev) ||
  59                                        device_may_wakeup(ldev)) ?
  60                                        "enabled" : "disabled",
  61                                        ldev->bus ? ldev->bus->name :
  62                                        "no-bus", dev_name(ldev));
  63                                put_device(ldev);
  64                        }
  65                }
  66
  67                mutex_unlock(&dev->physical_node_lock);
  68        }
  69        mutex_unlock(&acpi_device_lock);
  70        return 0;
  71}
  72
  73static void physical_device_enable_wakeup(struct acpi_device *adev)
  74{
  75        struct acpi_device_physical_node *entry;
  76
  77        mutex_lock(&adev->physical_node_lock);
  78
  79        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                }
  85
  86        mutex_unlock(&adev->physical_node_lock);
  87}
  88
  89static ssize_t
  90acpi_system_write_wakeup_device(struct file *file,
  91                                const char __user * buffer,
  92                                size_t count, loff_t * ppos)
  93{
  94        struct acpi_device *dev, *tmp;
  95        char strbuf[5];
  96        char str[5] = "";
  97
  98        if (count > 4)
  99                count = 4;
 100
 101        if (copy_from_user(strbuf, buffer, count))
 102                return -EFAULT;
 103        strbuf[count] = '\0';
 104        sscanf(strbuf, "%s", str);
 105
 106        mutex_lock(&acpi_device_lock);
 107        list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
 108                                 wakeup_list) {
 109                if (!dev->wakeup.flags.valid)
 110                        continue;
 111
 112                if (!strncmp(dev->pnp.bus_id, str, 4)) {
 113                        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                        }
 119                        break;
 120                }
 121        }
 122        mutex_unlock(&acpi_device_lock);
 123        return count;
 124}
 125
 126static int
 127acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
 128{
 129        return single_open(file, acpi_system_wakeup_device_seq_show,
 130                           PDE_DATA(inode));
 131}
 132
 133static 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,
 139};
 140
 141void __init acpi_sleep_proc_init(void)
 142{
 143        /* 'wakeup device' [R/W] */
 144        proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
 145                    acpi_root_dir, &acpi_system_wakeup_device_proc_ops);
 146}
 147