blob: e7abc6e3bba016faccb41606c75df5bc0461ecae [file] [log] [blame]
Zhang Ruia25ee922010-07-15 10:46:15 +08001/*
2 * debugfs.c - ACPI debugfs interface to userspace.
3 */
4
5#include <linux/init.h>
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/uaccess.h>
9#include <linux/debugfs.h>
10#include <acpi/acpi_drivers.h>
11
12#define _COMPONENT ACPI_SYSTEM_COMPONENT
13ACPI_MODULE_NAME("debugfs");
14
Thomas Renningeraecad432011-05-26 12:26:23 +020015struct dentry *acpi_debugfs_dir;
16static struct dentry *cm_dentry;
Zhang Ruic637e482010-07-15 10:46:17 +080017
Zhang Ruia25ee922010-07-15 10:46:15 +080018/* /sys/kernel/debug/acpi/custom_method */
19
20static ssize_t cm_write(struct file *file, const char __user * user_buf,
21 size_t count, loff_t *ppos)
22{
23 static char *buf;
Vasiliy Kulikov2949ad52011-02-19 14:18:08 +010024 static u32 max_size;
25 static u32 uncopied_bytes;
26
Zhang Ruia25ee922010-07-15 10:46:15 +080027 struct acpi_table_header table;
28 acpi_status status;
29
30 if (!(*ppos)) {
31 /* parse the table header to get the table length */
32 if (count <= sizeof(struct acpi_table_header))
33 return -EINVAL;
34 if (copy_from_user(&table, user_buf,
35 sizeof(struct acpi_table_header)))
36 return -EFAULT;
Vasiliy Kulikov2949ad52011-02-19 14:18:08 +010037 uncopied_bytes = max_size = table.length;
38 buf = kzalloc(max_size, GFP_KERNEL);
Zhang Ruia25ee922010-07-15 10:46:15 +080039 if (!buf)
40 return -ENOMEM;
41 }
42
Vasiliy Kulikov2949ad52011-02-19 14:18:08 +010043 if (buf == NULL)
Zhang Ruia25ee922010-07-15 10:46:15 +080044 return -EINVAL;
Vasiliy Kulikov2949ad52011-02-19 14:18:08 +010045
46 if ((*ppos > max_size) ||
47 (*ppos + count > max_size) ||
48 (*ppos + count < count) ||
49 (count > uncopied_bytes))
50 return -EINVAL;
Zhang Ruia25ee922010-07-15 10:46:15 +080051
52 if (copy_from_user(buf + (*ppos), user_buf, count)) {
53 kfree(buf);
Vasiliy Kulikov2949ad52011-02-19 14:18:08 +010054 buf = NULL;
Zhang Ruia25ee922010-07-15 10:46:15 +080055 return -EFAULT;
56 }
57
58 uncopied_bytes -= count;
59 *ppos += count;
60
61 if (!uncopied_bytes) {
62 status = acpi_install_method(buf);
63 kfree(buf);
Vasiliy Kulikov2949ad52011-02-19 14:18:08 +010064 buf = NULL;
Zhang Ruia25ee922010-07-15 10:46:15 +080065 if (ACPI_FAILURE(status))
66 return -EINVAL;
67 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
68 }
69
70 return count;
71}
72
73static const struct file_operations cm_fops = {
74 .write = cm_write,
Arnd Bergmann6038f372010-08-15 18:52:59 +020075 .llseek = default_llseek,
Zhang Ruia25ee922010-07-15 10:46:15 +080076};
77
Thomas Renningeraecad432011-05-26 12:26:23 +020078static int __init acpi_custom_method_init(void)
Zhang Ruia25ee922010-07-15 10:46:15 +080079{
Thomas Renningeraecad432011-05-26 12:26:23 +020080 if (!acpi_debugfs_dir)
81 return -ENOENT;
Zhang Ruia25ee922010-07-15 10:46:15 +080082
Dave Jonesed3aada2010-11-13 00:58:54 -050083 cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
Thomas Renningeraecad432011-05-26 12:26:23 +020084 acpi_debugfs_dir, NULL, &cm_fops);
Zhang Ruia25ee922010-07-15 10:46:15 +080085 if (!cm_dentry)
Thomas Renningeraecad432011-05-26 12:26:23 +020086 return -ENODEV;
Zhang Ruia25ee922010-07-15 10:46:15 +080087
88 return 0;
Thomas Renningeraecad432011-05-26 12:26:23 +020089}
Zhang Ruia25ee922010-07-15 10:46:15 +080090
Thomas Renningeraecad432011-05-26 12:26:23 +020091void __init acpi_debugfs_init(void)
92{
93 acpi_debugfs_dir = debugfs_create_dir("acpi", NULL);
94
95 acpi_custom_method_init();
Zhang Ruia25ee922010-07-15 10:46:15 +080096}